http-client-branch: (WebSocket) full-duplex DummyWebSocketServer; tests stabilization & fixes http-client-branch
authorprappo
Tue, 20 Mar 2018 00:30:20 +0000
branchhttp-client-branch
changeset 56324 3edf200fff01
parent 56323 cf43d0ee8959
child 56325 195d2970d981
http-client-branch: (WebSocket) full-duplex DummyWebSocketServer; tests stabilization & fixes
test/jdk/java/net/httpclient/websocket/AutomaticPong.java
test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java
test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java
test/jdk/java/net/httpclient/websocket/MessageQueueDriver.java
test/jdk/java/net/httpclient/websocket/MessageQueueTestDriver.java
test/jdk/java/net/httpclient/websocket/PendingOperations.java
test/jdk/java/net/httpclient/websocket/SendTest.java
test/jdk/java/net/httpclient/websocket/Support.java
test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java
test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java
test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java
test/jdk/java/net/httpclient/websocket/WebSocketTest.java
--- a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java	Tue Mar 20 00:30:20 2018 +0000
@@ -47,8 +47,8 @@
 
 public class AutomaticPong {
 
+    private DummyWebSocketServer server;
     private WebSocket webSocket;
-    private DummyWebSocketServer server;
 
     @AfterTest
     public void cleanup() {
@@ -105,7 +105,7 @@
      * to these messages automatically. According to RFC 6455 a WebSocket client
      * is free to reply only to the most recent Pings.
      *
-     * What is checked here is that
+     * What is checked here is that:
      *
      *     a) the order of Pong replies corresponds to the Pings received,
      *     b) the last Pong corresponds to the last Ping
@@ -118,17 +118,17 @@
         Frame.HeaderWriter w = new Frame.HeaderWriter();
         for (int i = 0; i < nPings; i++) {
             w.fin(true)
-                    .opcode(Frame.Opcode.PING)
-                    .noMask()
-                    .payloadLen(4)
-                    .write(buffer);
-            buffer.putInt(i);
+             .opcode(Frame.Opcode.PING)
+             .noMask()
+             .payloadLen(4)    // the length of the number of the Ping (int)
+             .write(buffer);
+            buffer.putInt(i);  // the number of the Ping (int)
         }
         w.fin(true)
-                .opcode(Frame.Opcode.CLOSE)
-                .noMask()
-                .payloadLen(2)
-                .write(buffer);
+         .opcode(Frame.Opcode.CLOSE)
+         .noMask()
+         .payloadLen(2)
+        .write(buffer);
         buffer.putChar((char) 1000);
         buffer.flip();
         server = Support.serverWithCannedData(buffer.array());
@@ -139,7 +139,7 @@
                 .buildAsync(server.getURI(), listener)
                 .join();
         List<MockListener.Invocation> inv = listener.invocations();
-        assertEquals(inv.size(), nPings + 2); // onOpen + onClose + n*onPing
+        assertEquals(inv.size(), nPings + 2); // n * onPing + onOpen + onClose
 
         ByteBuffer data = server.read();
         Frame.Reader reader = new Frame.Reader();
@@ -196,6 +196,8 @@
                 int n = number.getInt();
                 System.out.printf("pong number=%s%n", n);
                 number.clear();
+                // a Pong with the number less than the maximum of Pongs already
+                // received MUST never be received
                 if (i >= n) {
                     fail(String.format("i=%s, n=%s", i, n));
                 }
@@ -213,6 +215,6 @@
 
     @DataProvider(name = "nPings")
     public Object[][] nPings() {
-        return new Object[][]{{1}, {2}, {4}, {8}, {9}, {1023}};
+        return new Object[][]{{1}, {2}, {4}, {8}, {9}, {256}};
     }
 }
--- a/test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java	Tue Mar 20 00:30:20 2018 +0000
@@ -21,12 +21,6 @@
  * questions.
  */
 
-import java.net.http.HttpClient;
-import java.net.http.WebSocket;
-
-import java.io.IOException;
-import java.net.URI;
-
 /*
  * @test
  * @bug 8164625
@@ -34,6 +28,12 @@
  * @build DummyWebSocketServer
  * @run main/othervm -Djdk.httpclient.HttpClient.log=trace ConnectionHandoverTest
  */
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.WebSocket;
+
 public class ConnectionHandoverTest {
     /*
      * An I/O channel associated with the connection is closed by WebSocket.abort().
--- a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java	Tue Mar 20 00:30:20 2018 +0000
@@ -26,6 +26,7 @@
 import java.io.UncheckedIOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.StandardSocketOptions;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
@@ -88,7 +89,7 @@
     private final Thread thread;
     private volatile ServerSocketChannel ssc;
     private volatile InetSocketAddress address;
-    private ByteBuffer read = ByteBuffer.allocate(1024);
+    private ByteBuffer read = ByteBuffer.allocate(16384);
     private final CountDownLatch readReady = new CountDownLatch(1);
 
     public DummyWebSocketServer() {
@@ -104,6 +105,7 @@
                     SocketChannel channel = ssc.accept();
                     err.println("Accepted: " + channel);
                     try {
+                        channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
                         channel.configureBlocking(true);
                         StringBuilder request = new StringBuilder();
                         if (!readRequest(channel, request)) {
@@ -122,7 +124,7 @@
                     }
                 }
             } catch (ClosedByInterruptException ignored) {
-            } catch (IOException e) {
+            } catch (Exception e) {
                 err.println(e);
             } finally {
                 close(ssc);
@@ -133,11 +135,11 @@
         thread.setDaemon(false);
     }
 
-    protected void serve(SocketChannel channel) throws IOException {
+    protected void read(SocketChannel ch) throws IOException {
         // Read until the thread is interrupted or an error occurred
         // or the input is shutdown
-        ByteBuffer b = ByteBuffer.allocate(1024);
-        while (channel.read(b) != -1) {
+        ByteBuffer b = ByteBuffer.allocate(65536);
+        while (ch.read(b) != -1) {
             b.flip();
             if (read.remaining() < b.remaining()) {
                 int required = read.capacity() - read.remaining() + b.remaining();
@@ -149,9 +151,34 @@
             read.put(b);
             b.clear();
         }
-        ByteBuffer close = ByteBuffer.wrap(new byte[]{(byte) 0x88, 0x00});
-        while (close.hasRemaining()) {
-            channel.write(close);
+    }
+
+    protected void write(SocketChannel ch) throws IOException { }
+
+    protected final void serve(SocketChannel channel)
+            throws InterruptedException
+    {
+        Thread reader = new Thread(() -> {
+            try {
+                read(channel);
+            } catch (IOException ignored) { }
+        });
+        Thread writer = new Thread(() -> {
+            try {
+                write(channel);
+            } catch (IOException ignored) { }
+        });
+        reader.start();
+        writer.start();
+        try {
+            reader.join();
+        } finally {
+            reader.interrupt();
+            try {
+                writer.join();
+            } finally {
+                writer.interrupt();
+            }
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/websocket/MessageQueueDriver.java	Tue Mar 20 00:30:20 2018 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8159053
+ * @modules java.net.http/jdk.internal.net.http.websocket:open
+ * @run testng/othervm
+ *      --add-reads java.net.http=ALL-UNNAMED
+ *      java.net.http/jdk.internal.net.http.websocket.MessageQueueTest
+ */
+public final class MessageQueueDriver { }
--- a/test/jdk/java/net/httpclient/websocket/MessageQueueTestDriver.java	Mon Mar 19 21:04:01 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8159053
- * @modules java.net.http/jdk.internal.net.http.websocket:open
- * @run testng/othervm
- *      --add-reads java.net.http=ALL-UNNAMED
- *      java.net.http/jdk.internal.net.http.websocket.MessageQueueTest
- */
-public final class MessageQueueTestDriver { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/websocket/PendingOperations.java	Tue Mar 20 00:30:20 2018 +0000
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @build DummyWebSocketServer
+ * @run testng/othervm/timeout=300
+ *      -Djdk.internal.httpclient.websocket.debug=true
+ *       PendingOperations
+ */
+
+import org.testng.annotations.AfterTest;
+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.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static java.net.http.HttpClient.newHttpClient;
+
+public class PendingOperations {
+
+    private static final Class<IllegalStateException> ISE = IllegalStateException.class;
+    private static final Class<IOException> IOE = IOException.class;
+
+    private DummyWebSocketServer server;
+    private WebSocket webSocket;
+
+    @AfterTest
+    public void cleanup() {
+        server.close();
+        webSocket.abort();
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingTextPingClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = 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
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfText = webSocket.sendText(data, last);
+            try {
+                cfText.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendText("", true));
+        assertFails(ISE, webSocket.sendText("", false));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), true));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), false));
+        CompletableFuture<WebSocket> cfPing = webSocket.sendPing(ByteBuffer.allocate(125));
+        assertHangs(cfPing);
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfClose = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfText);
+        assertFails(IOE, cfPing);
+        assertFails(IOE, cfClose);
+    }
+
+    /* shortcut */
+    public static void assertHangs(CompletionStage<?> stage) {
+        Support.assertHangs(stage);
+    }
+
+    /* shortcut */
+    private static void assertFails(Class<? extends Throwable> clazz,
+                                    CompletionStage<?> stage) {
+        Support.assertCompletesExceptionally(clazz, stage);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingTextPongClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = 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
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfText = webSocket.sendText(data, last);
+            try {
+                cfText.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendText("", true));
+        assertFails(ISE, webSocket.sendText("", false));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), true));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), false));
+        CompletableFuture<WebSocket> cfPong = webSocket.sendPong(ByteBuffer.allocate(125));
+        assertHangs(cfPong);
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfClose = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfText);
+        assertFails(IOE, cfPong);
+        assertFails(IOE, cfClose);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingBinaryPingClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        ByteBuffer data = ByteBuffer.allocate(65536);
+        CompletableFuture<WebSocket> cfBinary;
+        for (int i = 0; ; i++) {  // fill up the send buffer
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfBinary = webSocket.sendBinary(data, last);
+            try {
+                cfBinary.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendText("", true));
+        assertFails(ISE, webSocket.sendText("", false));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), true));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), false));
+        CompletableFuture<WebSocket> cfPing = webSocket.sendPing(ByteBuffer.allocate(125));
+        assertHangs(cfPing);
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfClose = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfBinary);
+        assertFails(IOE, cfPing);
+        assertFails(IOE, cfClose);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingBinaryPongClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        ByteBuffer data = ByteBuffer.allocate(65536);
+        CompletableFuture<WebSocket> cfBinary;
+        for (int i = 0; ; i++) {  // fill up the send buffer
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfBinary = webSocket.sendBinary(data, last);
+            try {
+                cfBinary.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendText("", true));
+        assertFails(ISE, webSocket.sendText("", false));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), true));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(0), false));
+        CompletableFuture<WebSocket> cfPong = webSocket.sendPong(ByteBuffer.allocate(125));
+        assertHangs(cfPong);
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfClose = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfBinary);
+        assertFails(IOE, cfPong);
+        assertFails(IOE, cfClose);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPingTextClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = 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
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfPing = webSocket.sendPing(data);
+            try {
+                cfPing.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfText = webSocket.sendText("hello", last);
+        assertHangs(cfText);
+        CompletableFuture<WebSocket> cfClose
+                = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfPing);
+        assertFails(IOE, cfText);
+        assertFails(IOE, cfClose);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPingBinaryClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = 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
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfPing = webSocket.sendPing(data);
+            try {
+                cfPing.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfBinary
+                = webSocket.sendBinary(ByteBuffer.allocate(4), last);
+        assertHangs(cfBinary);
+        CompletableFuture<WebSocket> cfClose
+                = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfPing);
+        assertFails(IOE, cfBinary);
+        assertFails(IOE, cfClose);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPongTextClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = 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
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfPong = webSocket.sendPong(data);
+            try {
+                cfPong.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfText = webSocket.sendText("hello", last);
+        assertHangs(cfText);
+        CompletableFuture<WebSocket> cfClose
+                = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfPong);
+        assertFails(IOE, cfText);
+        assertFails(IOE, cfClose);
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPongBinaryClose(boolean last) throws Exception {
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = 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
+            long start = System.currentTimeMillis();
+            System.out.printf("begin cycle #%s at %s%n", i, start);
+            cfPong = webSocket.sendPong(data);
+            try {
+                cfPong.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                long stop = System.currentTimeMillis();
+                System.out.printf("end cycle #%s at %s (%s ms)%n", i, stop, stop - start);
+            }
+        }
+        assertFails(ISE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(ISE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        CompletableFuture<WebSocket> cfBinary
+                = webSocket.sendBinary(ByteBuffer.allocate(4), last);
+        assertHangs(cfBinary);
+        CompletableFuture<WebSocket> cfClose
+                = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+        assertHangs(cfClose);
+        webSocket.abort();
+        assertFails(IOE, cfPong);
+        assertFails(IOE, cfBinary);
+        assertFails(IOE, cfClose);
+    }
+
+    @DataProvider(name = "booleans")
+    public Object[][] booleans() {
+        return new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}};
+    }
+}
--- a/test/jdk/java/net/httpclient/websocket/SendTest.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/SendTest.java	Tue Mar 20 00:30:20 2018 +0000
@@ -29,6 +29,7 @@
  *       SendTest
  */
 
+import org.testng.annotations.AfterTest;
 import org.testng.annotations.Test;
 
 import java.io.IOException;
@@ -49,33 +50,40 @@
 
     private static final Class<NullPointerException> NPE = NullPointerException.class;
 
+    private DummyWebSocketServer server;
+    private WebSocket webSocket;
+
+    @AfterTest
+    public void cleanup() {
+        server.close();
+        webSocket.abort();
+    }
+
     @Test
     public void sendMethodsThrowNPE() throws IOException {
-        try (DummyWebSocketServer server = new DummyWebSocketServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
+        server = new DummyWebSocketServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
 
-            assertThrows(NPE, () -> ws.sendText(null, false));
-            assertThrows(NPE, () -> ws.sendText(null, true));
-            assertThrows(NPE, () -> ws.sendBinary(null, false));
-            assertThrows(NPE, () -> ws.sendBinary(null, true));
-            assertThrows(NPE, () -> ws.sendPing(null));
-            assertThrows(NPE, () -> ws.sendPong(null));
-            assertThrows(NPE, () -> ws.sendClose(NORMAL_CLOSURE, null));
+        assertThrows(NPE, () -> webSocket.sendText(null, false));
+        assertThrows(NPE, () -> webSocket.sendText(null, true));
+        assertThrows(NPE, () -> webSocket.sendBinary(null, false));
+        assertThrows(NPE, () -> webSocket.sendBinary(null, true));
+        assertThrows(NPE, () -> webSocket.sendPing(null));
+        assertThrows(NPE, () -> webSocket.sendPong(null));
+        assertThrows(NPE, () -> webSocket.sendClose(NORMAL_CLOSURE, null));
 
-            ws.abort();
+        webSocket.abort();
 
-            assertThrows(NPE, () -> ws.sendText(null, false));
-            assertThrows(NPE, () -> ws.sendText(null, true));
-            assertThrows(NPE, () -> ws.sendBinary(null, false));
-            assertThrows(NPE, () -> ws.sendBinary(null, true));
-            assertThrows(NPE, () -> ws.sendPing(null));
-            assertThrows(NPE, () -> ws.sendPong(null));
-            assertThrows(NPE, () -> ws.sendClose(NORMAL_CLOSURE, null));
-        }
+        assertThrows(NPE, () -> webSocket.sendText(null, false));
+        assertThrows(NPE, () -> webSocket.sendText(null, true));
+        assertThrows(NPE, () -> webSocket.sendBinary(null, false));
+        assertThrows(NPE, () -> webSocket.sendBinary(null, true));
+        assertThrows(NPE, () -> webSocket.sendPing(null));
+        assertThrows(NPE, () -> webSocket.sendPong(null));
+        assertThrows(NPE, () -> webSocket.sendClose(NORMAL_CLOSURE, null));
     }
 
     // TODO: request in onClose/onError
@@ -84,148 +92,137 @@
 
     @Test
     public void sendCloseCompleted() throws IOException {
-        try (DummyWebSocketServer server = new DummyWebSocketServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
-            ws.sendClose(NORMAL_CLOSURE, "").join();
-            assertTrue(ws.isOutputClosed());
-            assertEquals(ws.getSubprotocol(), "");
-            ws.request(1); // No exceptions must be thrown
-        }
+        server = new DummyWebSocketServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        webSocket.sendClose(NORMAL_CLOSURE, "").join();
+        assertTrue(webSocket.isOutputClosed());
+        assertEquals(webSocket.getSubprotocol(), "");
+        webSocket.request(1); // No exceptions must be thrown
     }
 
     @Test
     public void sendClosePending() throws Exception {
-        try (DummyWebSocketServer server = Support.notReadingServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        ByteBuffer data = ByteBuffer.allocate(65536);
+        for (int i = 0; ; i++) { // fill up the send buffer
+            System.out.printf("begin cycle #%s at %s%n",
+                              i, System.currentTimeMillis());
             try {
-                ByteBuffer data = ByteBuffer.allocate(65536);
-                for (int i = 0; ; i++) { // fill up the send buffer
-                    System.out.printf("begin cycle #%s at %s%n",
-                            i, System.currentTimeMillis());
-                    try {
-                        ws.sendBinary(data, true).get(10, TimeUnit.SECONDS);
-                        data.clear();
-                    } catch (TimeoutException e) {
-                        break;
-                    } finally {
-                        System.out.printf("end cycle #%s at %s%n",
-                                i, System.currentTimeMillis());
-                    }
-                }
-                CompletableFuture<WebSocket> cf = ws.sendClose(NORMAL_CLOSURE, "");
-                // The output closes even if the Close message has not been sent
-                assertFalse(cf.isDone());
-                assertTrue(ws.isOutputClosed());
-                assertEquals(ws.getSubprotocol(), "");
+                webSocket.sendBinary(data, true).get(10, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
             } finally {
-                ws.abort();
+                System.out.printf("end cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
             }
         }
+        CompletableFuture<WebSocket> cf = webSocket.sendClose(NORMAL_CLOSURE, "");
+        // The output closes even if the Close message has not been sent
+        assertFalse(cf.isDone());
+        assertTrue(webSocket.isOutputClosed());
+        assertEquals(webSocket.getSubprotocol(), "");
     }
 
     @Test
     public void abortPendingSendBinary() throws Exception {
-        try (DummyWebSocketServer server = Support.notReadingServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
-            ByteBuffer data = ByteBuffer.allocate(65536);
-            CompletableFuture<WebSocket> cf = null;
-            for (int i = 0; ; i++) {  // fill up the send buffer
-                System.out.printf("begin cycle #%s at %s%n",
-                        i, System.currentTimeMillis());
-                try {
-                    cf = ws.sendBinary(data, true);
-                    cf.get(10, TimeUnit.SECONDS);
-                    data.clear();
-                } catch (TimeoutException e) {
-                    break;
-                } finally {
-                    System.out.printf("end cycle #%s at %s%n",
-                            i, System.currentTimeMillis());
-                }
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = newHttpClient()
+                .newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        ByteBuffer data = ByteBuffer.allocate(65536);
+        CompletableFuture<WebSocket> cf = null;
+        for (int i = 0; ; i++) {  // fill up the send buffer
+            System.out.printf("begin cycle #%s at %s%n",
+                              i, System.currentTimeMillis());
+            try {
+                cf = webSocket.sendBinary(data, true);
+                cf.get(5, TimeUnit.SECONDS);
+                data.clear();
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                System.out.printf("end cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
             }
-            ws.abort();
-            assertTrue(ws.isOutputClosed());
-            assertTrue(ws.isInputClosed());
-            Support.assertFails(IOException.class, cf);
         }
+        webSocket.abort();
+        assertTrue(webSocket.isOutputClosed());
+        assertTrue(webSocket.isInputClosed());
+        Support.assertFails(IOException.class, cf);
     }
 
     @Test
     public void abortPendingSendText() throws Exception {
-        try (DummyWebSocketServer server = Support.notReadingServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
-            String data = Support.stringWith2NBytes(32768);
-            CompletableFuture<WebSocket> cf = null;
-            for (int i = 0; ; i++) {  // fill up the send buffer
-                System.out.printf("begin cycle #%s at %s%n",
-                        i, System.currentTimeMillis());
-                try {
-                    cf = ws.sendText(data, true);
-                    cf.get(10, TimeUnit.SECONDS);
-                } catch (TimeoutException e) {
-                    break;
-                } finally {
-                    System.out.printf("end cycle #%s at %s%n",
-                            i, System.currentTimeMillis());
-                }
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = newHttpClient()
+                .newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        String data = Support.stringWith2NBytes(32768);
+        CompletableFuture<WebSocket> cf = null;
+        for (int i = 0; ; i++) {  // fill up the send buffer
+            System.out.printf("begin cycle #%s at %s%n",
+                              i, System.currentTimeMillis());
+            try {
+                cf = webSocket.sendText(data, true);
+                cf.get(5, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                System.out.printf("end cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
             }
-            ws.abort();
-            assertTrue(ws.isOutputClosed());
-            assertTrue(ws.isInputClosed());
-            Support.assertFails(IOException.class, cf);
         }
+        webSocket.abort();
+        assertTrue(webSocket.isOutputClosed());
+        assertTrue(webSocket.isInputClosed());
+        Support.assertFails(IOException.class, cf);
     }
 
     @Test // FIXME: TO BE REMOVED as we agreed upon no timeout in sendClose
     public void sendCloseTimeout() throws Exception {
-        try (DummyWebSocketServer server = Support.notReadingServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
-            String data = Support.stringWith2NBytes(32768);
-            CompletableFuture<WebSocket> cf = null;
-            for (int i = 0; ; i++) {  // fill up the send buffer
-                System.out.printf("begin cycle #%s at %s%n",
-                        i, System.currentTimeMillis());
-                try {
-                    cf = ws.sendText(data, true);
-                    cf.get(10, TimeUnit.SECONDS);
-                } catch (TimeoutException e) {
-                    break;
-                } finally {
-                    System.out.printf("end cycle #%s at %s%n",
-                            i, System.currentTimeMillis());
-                }
+        server = Support.notReadingServer();
+        server.open();
+        webSocket = newHttpClient()
+                .newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        String data = Support.stringWith2NBytes(32768);
+        CompletableFuture<WebSocket> cf = null;
+        for (int i = 0; ; i++) {  // fill up the send buffer
+            System.out.printf("begin cycle #%s at %s%n",
+                              i, System.currentTimeMillis());
+            try {
+                cf = webSocket.sendText(data, true);
+                cf.get(10, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                break;
+            } finally {
+                System.out.printf("end cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
             }
-            long before = System.currentTimeMillis();
-            Support.assertFails(IOException.class,
-                    ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok"));
-            long after = System.currentTimeMillis();
-            // default timeout should be 30 seconds
-            long elapsed = after - before;
-            System.out.printf("Elapsed %s ms%n", elapsed);
-            assertTrue(elapsed >= 29_000, String.valueOf(elapsed));
-            assertTrue(ws.isOutputClosed());
-            assertTrue(ws.isInputClosed());
-            Support.assertFails(IOException.class, cf);
         }
+        long before = System.currentTimeMillis();
+        Support.assertFails(IOException.class,
+                            webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok"));
+        long after = System.currentTimeMillis();
+        // default timeout should be 30 seconds
+        long elapsed = after - before;
+        System.out.printf("Elapsed %s ms%n", elapsed);
+        assertTrue(elapsed >= 29_000, String.valueOf(elapsed));
+        assertTrue(webSocket.isOutputClosed());
+        assertTrue(webSocket.isInputClosed());
+        Support.assertFails(IOException.class, cf);
     }
 }
--- a/test/jdk/java/net/httpclient/websocket/Support.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/Support.java	Tue Mar 20 00:30:20 2018 +0000
@@ -90,10 +90,20 @@
         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);
+            protected void write(SocketChannel ch) throws IOException {
+                int off = 0; int n = 1; // 1 byte at a time
+                while (off + n < copy.length + n) {
+//                    try {
+//                        TimeUnit.MICROSECONDS.sleep(500);
+//                    } catch (InterruptedException e) {
+//                        return;
+//                    }
+                    int len = Math.min(copy.length - off, n);
+                    ByteBuffer bytes = ByteBuffer.wrap(copy, off, len);
+                    off += len;
+                    ch.write(bytes);
+                }
+                super.write(ch);
             }
         };
     }
@@ -106,7 +116,7 @@
     public static DummyWebSocketServer notReadingServer() {
         return new DummyWebSocketServer() {
             @Override
-            protected void serve(SocketChannel channel) throws IOException {
+            protected void read(SocketChannel ch) throws IOException {
                 try {
                     Thread.sleep(Long.MAX_VALUE);
                 } catch (InterruptedException e) {
--- a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java	Tue Mar 20 00:30:20 2018 +0000
@@ -30,6 +30,7 @@
  *          jdk.httpserver
  * @run testng/othervm -Djdk.internal.httpclient.debug=true WSHandshakeExceptionTest
  */
+
 import com.sun.net.httpserver.HttpServer;
 import com.sun.net.httpserver.HttpsConfigurator;
 import com.sun.net.httpserver.HttpsServer;
--- a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java	Tue Mar 20 00:30:20 2018 +0000
@@ -21,6 +21,12 @@
  * questions.
  */
 
+/*
+ * @test
+ * @bug 8159053
+ * @run testng/othervm WebSocketBuilderTest
+ */
+
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -37,12 +43,6 @@
 import static org.testng.Assert.assertThrows;
 
 /*
- * @test
- * @bug 8159053
- * @run testng/othervm WebSocketBuilderTest
- */
-
-/*
  * In some places in this test a new String is created out of a string literal.
  * The idea is to make sure the code under test relies on something better than
  * the reference equality ( == ) for string equality checks.
--- a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java	Tue Mar 20 00:30:20 2018 +0000
@@ -21,6 +21,18 @@
  * questions.
  */
 
+/*
+ * @test
+ * @bug 8159053
+ *
+ *
+ * @run testng/othervm
+ *      -Djdk.internal.httpclient.websocket.debug=true
+ *      -Djdk.internal.httpclient.debug=true
+ *      -Djdk.httpclient.websocket.writeBufferSize=1024
+ *      -Djdk.httpclient.websocket.intermediateBufferSize=2048 WebSocketExtendedTest
+ */
+
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -36,17 +48,6 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
-/*
- * @test
- * @bug 8159053
- *
- *
- * @run testng/othervm
- *      -Djdk.internal.httpclient.websocket.debug=true
- *      -Djdk.internal.httpclient.debug=true
- *      -Djdk.httpclient.websocket.writeBufferSize=1024
- *      -Djdk.httpclient.websocket.intermediateBufferSize=2048 WebSocketExtendedTest
- */
 
 /*
  * This battery of tests exercises sending data (Text/Binary) messages with
--- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java	Mon Mar 19 21:04:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java	Tue Mar 20 00:30:20 2018 +0000
@@ -24,34 +24,29 @@
 /*
  * @test
  * @build DummyWebSocketServer
- * @run testng/othervm/timeout=600
+ * @run testng/othervm
  *      -Djdk.internal.httpclient.websocket.debug=true
  *       WebSocketTest
  */
 
-import org.testng.annotations.DataProvider;
+import org.testng.annotations.AfterTest;
 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.charset.StandardCharsets;
 import java.util.ArrayList;
 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 static java.net.http.HttpClient.newHttpClient;
 import static java.net.http.WebSocket.NORMAL_CLOSURE;
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
 
 public class WebSocketTest {
 
@@ -65,508 +60,195 @@
         Support.assertCompletesExceptionally(clazz, stage);
     }
 
-    @Test
-    public void illegalArgument() throws IOException {
-        try (DummyWebSocketServer server = new DummyWebSocketServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
-
-            assertFails(IAE, ws.sendPing(ByteBuffer.allocate(126)));
-            assertFails(IAE, ws.sendPing(ByteBuffer.allocate(127)));
-            assertFails(IAE, ws.sendPing(ByteBuffer.allocate(128)));
-            assertFails(IAE, ws.sendPing(ByteBuffer.allocate(129)));
-            assertFails(IAE, ws.sendPing(ByteBuffer.allocate(256)));
-
-            assertFails(IAE, ws.sendPong(ByteBuffer.allocate(126)));
-            assertFails(IAE, ws.sendPong(ByteBuffer.allocate(127)));
-            assertFails(IAE, ws.sendPong(ByteBuffer.allocate(128)));
-            assertFails(IAE, ws.sendPong(ByteBuffer.allocate(129)));
-            assertFails(IAE, ws.sendPong(ByteBuffer.allocate(256)));
-
-            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, 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"));
-            assertFails(IAE, ws.sendClose(0, "a reason"));
-            assertFails(IAE, ws.sendClose(1, "a reason"));
-            assertFails(IAE, ws.sendClose(500, "a reason"));
-            assertFails(IAE, ws.sendClose(998, "a reason"));
-            assertFails(IAE, ws.sendClose(999, "a reason"));
-            assertFails(IAE, ws.sendClose(1002, "a reason"));
-            assertFails(IAE, ws.sendClose(1003, "a reason"));
-            assertFails(IAE, ws.sendClose(1006, "a reason"));
-            assertFails(IAE, ws.sendClose(1007, "a reason"));
-            assertFails(IAE, ws.sendClose(1009, "a reason"));
-            assertFails(IAE, ws.sendClose(1010, "a reason"));
-            assertFails(IAE, ws.sendClose(1012, "a reason"));
-            assertFails(IAE, ws.sendClose(1013, "a reason"));
-            assertFails(IAE, ws.sendClose(1015, "a reason"));
-            assertFails(IAE, ws.sendClose(5000, "a reason"));
-            assertFails(IAE, ws.sendClose(32768, "a reason"));
-            assertFails(IAE, ws.sendClose(65535, "a reason"));
-            assertFails(IAE, ws.sendClose(65536, "a reason"));
-            assertFails(IAE, ws.sendClose(Integer.MAX_VALUE, "a reason"));
-            assertFails(IAE, ws.sendClose(Integer.MIN_VALUE, "a reason"));
-
-            assertThrows(IAE, () -> ws.request(Integer.MIN_VALUE));
-            assertThrows(IAE, () -> ws.request(Long.MIN_VALUE));
-            assertThrows(IAE, () -> ws.request(-1));
-            assertThrows(IAE, () -> ws.request(0));
-        }
-    }
-
-    @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 DummyWebSocketServer server;
+    private WebSocket webSocket;
 
-            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);
-        }
-    }
-
-    /* shortcut */
-    public static void assertHangs(CompletionStage<?> stage) {
-        Support.assertHangs(stage);
-    }
-
-    @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);
-        }
+    @AfterTest
+    public void cleanup() {
+        server.close();
+        webSocket.abort();
     }
 
-    @Test(dataProvider = "booleans")
-    public void pendingBinaryPingClose(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(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 {
-                    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.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 illegalArgument() throws IOException {
+        server = new DummyWebSocketServer();
+        server.open();
+        webSocket = newHttpClient()
+                .newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
 
-    @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();
+        assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(126)));
+        assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(127)));
+        assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(128)));
+        assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(129)));
+        assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(256)));
 
-            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 {
-                    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.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);
-        }
-    }
+        assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(126)));
+        assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(127)));
+        assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(128)));
+        assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(129)));
+        assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(256)));
 
-    @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();
+        assertFails(IOE, webSocket.sendText(Support.incompleteString(), true));
+        assertFails(IOE, webSocket.sendText(Support.incompleteString(), false));
+        assertFails(IOE, webSocket.sendText(Support.malformedString(), true));
+        assertFails(IOE, webSocket.sendText(Support.malformedString(), false));
 
-            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);
-        }
-    }
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(124)));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(125)));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(128)));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(256)));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(257)));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWith2NBytes((123 / 2) + 1)));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.malformedString()));
+        assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.incompleteString()));
 
-    @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);
-        }
-    }
+        assertFails(IAE, webSocket.sendClose(-2, "a reason"));
+        assertFails(IAE, webSocket.sendClose(-1, "a reason"));
+        assertFails(IAE, webSocket.sendClose(0, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1, "a reason"));
+        assertFails(IAE, webSocket.sendClose(500, "a reason"));
+        assertFails(IAE, webSocket.sendClose(998, "a reason"));
+        assertFails(IAE, webSocket.sendClose(999, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1002, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1003, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1006, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1007, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1009, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1010, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1012, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1013, "a reason"));
+        assertFails(IAE, webSocket.sendClose(1015, "a reason"));
+        assertFails(IAE, webSocket.sendClose(5000, "a reason"));
+        assertFails(IAE, webSocket.sendClose(32768, "a reason"));
+        assertFails(IAE, webSocket.sendClose(65535, "a reason"));
+        assertFails(IAE, webSocket.sendClose(65536, "a reason"));
+        assertFails(IAE, webSocket.sendClose(Integer.MAX_VALUE, "a reason"));
+        assertFails(IAE, webSocket.sendClose(Integer.MIN_VALUE, "a reason"));
 
-    @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);
-        }
+        assertThrows(IAE, () -> webSocket.request(Integer.MIN_VALUE));
+        assertThrows(IAE, () -> webSocket.request(Long.MIN_VALUE));
+        assertThrows(IAE, () -> webSocket.request(-1));
+        assertThrows(IAE, () -> webSocket.request(0));
     }
 
     @Test
     public void partialBinaryThenText() throws IOException {
-        try (DummyWebSocketServer server = new DummyWebSocketServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
-
-            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();
-        }
+        server = new DummyWebSocketServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
+        webSocket.sendBinary(ByteBuffer.allocate(16), false).join();
+        assertFails(ISE, webSocket.sendText("text", false));
+        assertFails(ISE, webSocket.sendText("text", true));
+        // Pings & Pongs are fine
+        webSocket.sendPing(ByteBuffer.allocate(125)).join();
+        webSocket.sendPong(ByteBuffer.allocate(125)).join();
     }
 
     @Test
     public void partialTextThenBinary() throws IOException {
-        try (DummyWebSocketServer server = new DummyWebSocketServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
+        server = new DummyWebSocketServer();
+        server.open();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
 
-            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();
-        }
+        webSocket.sendText("text", false).join();
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(16), false));
+        assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(16), true));
+        // Pings & Pongs are fine
+        webSocket.sendPing(ByteBuffer.allocate(125)).join();
+        webSocket.sendPong(ByteBuffer.allocate(125)).join();
     }
 
     @Test
     public void sendMethodsThrowIOE1() throws IOException {
-        try (DummyWebSocketServer server = new DummyWebSocketServer()) {
-            server.open();
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
-                    .join();
+        server = new DummyWebSocketServer();
+        server.open();
+        webSocket = newHttpClient()
+                .newWebSocketBuilder()
+                .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                .join();
 
-            ws.sendClose(NORMAL_CLOSURE, "ok").join();
+        webSocket.sendClose(NORMAL_CLOSURE, "ok").join();
 
-            assertFails(IOE, ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok"));
+        assertFails(IOE, webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok"));
 
-            assertFails(IOE, ws.sendText("", true));
-            assertFails(IOE, ws.sendText("", false));
-            assertFails(IOE, ws.sendText("abc", true));
-            assertFails(IOE, ws.sendText("abc", false));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(0), true));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(0), false));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(1), true));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(1), false));
+        assertFails(IOE, webSocket.sendText("", true));
+        assertFails(IOE, webSocket.sendText("", false));
+        assertFails(IOE, webSocket.sendText("abc", true));
+        assertFails(IOE, webSocket.sendText("abc", false));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), true));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), false));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), true));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), false));
 
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(125)));
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(124)));
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(1)));
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(0)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(124)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(1)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(0)));
 
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(125)));
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(124)));
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(1)));
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(0)));
-        }
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124)));
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1)));
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0)));
     }
 
     @Test
     public void sendMethodsThrowIOE2() throws Exception {
-        try (DummyWebSocketServer server = Support.serverWithCannedData(0x88, 0x00)) {
-            server.open();
-            CompletableFuture<Void> onCloseCalled = new CompletableFuture<>();
-            CompletableFuture<Void> canClose = new CompletableFuture<>();
+        server = Support.serverWithCannedData(0x88, 0x00);
+        server.open();
+        CompletableFuture<Void> onCloseCalled = new CompletableFuture<>();
+        CompletableFuture<Void> canClose = new CompletableFuture<>();
 
-            WebSocket ws = newHttpClient()
-                    .newWebSocketBuilder()
-                    .buildAsync(server.getURI(), new WebSocket.Listener() {
-                        @Override
-                        public CompletionStage<?> onClose(WebSocket webSocket,
-                                                          int statusCode,
-                                                          String reason) {
-                            System.out.printf("onClose(%s, '%s')%n", statusCode, reason);
-                            onCloseCalled.complete(null);
-                            return canClose;
-                        }
+        WebSocket.Listener listener = new WebSocket.Listener() {
+            @Override
+            public CompletionStage<?> onClose(WebSocket webSocket,
+                                              int statusCode,
+                                              String reason) {
+                System.out.printf("onClose(%s, '%s')%n", statusCode, reason);
+                onCloseCalled.complete(null);
+                return canClose;
+            }
 
-                        @Override
-                        public void onError(WebSocket webSocket, Throwable error) {
-                            System.out.println("onError(" + error + ")");
-                            onCloseCalled.completeExceptionally(error);
-                        }
-                    })
-                    .join();
+            @Override
+            public void onError(WebSocket webSocket, Throwable error) {
+                System.out.println("onError(" + error + ")");
+                onCloseCalled.completeExceptionally(error);
+            }
+        };
 
-            onCloseCalled.join();      // Wait for onClose to be called
-            canClose.complete(null);   // Signal to the WebSocket it can close the output
-            TimeUnit.SECONDS.sleep(5); // Give canClose some time to reach the WebSocket
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), listener)
+                .join();
 
-            assertFails(IOE, ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok"));
+        onCloseCalled.join();      // Wait for onClose to be called
+        canClose.complete(null);   // Signal to the WebSocket it can close the output
+        TimeUnit.SECONDS.sleep(5); // Give canClose some time to reach the WebSocket
+
+        assertFails(IOE, webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok"));
 
-            assertFails(IOE, ws.sendText("", true));
-            assertFails(IOE, ws.sendText("", false));
-            assertFails(IOE, ws.sendText("abc", true));
-            assertFails(IOE, ws.sendText("abc", false));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(0), true));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(0), false));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(1), true));
-            assertFails(IOE, ws.sendBinary(ByteBuffer.allocate(1), false));
+        assertFails(IOE, webSocket.sendText("", true));
+        assertFails(IOE, webSocket.sendText("", false));
+        assertFails(IOE, webSocket.sendText("abc", true));
+        assertFails(IOE, webSocket.sendText("abc", false));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), true));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), false));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), true));
+        assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), false));
 
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(125)));
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(124)));
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(1)));
-            assertFails(IOE, ws.sendPing(ByteBuffer.allocate(0)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(125)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(124)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(1)));
+        assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(0)));
 
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(125)));
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(124)));
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(1)));
-            assertFails(IOE, ws.sendPong(ByteBuffer.allocate(0)));
-        }
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(125)));
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124)));
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1)));
+        assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0)));
     }
 
     @Test
@@ -594,71 +276,69 @@
         };
         CompletableFuture<List<byte[]>> actual = new CompletableFuture<>();
 
-        try (DummyWebSocketServer server = Support.serverWithCannedData(binary)) {
-            server.open();
+        server = Support.serverWithCannedData(binary);
+        server.open();
 
-            WebSocket.Listener listener = new WebSocket.Listener() {
+        WebSocket.Listener listener = new WebSocket.Listener() {
 
-                List<byte[]> collectedBytes = new ArrayList<>();
-                ByteBuffer binary = ByteBuffer.allocate(1024);
+            List<byte[]> collectedBytes = new ArrayList<>();
+            ByteBuffer buffer = ByteBuffer.allocate(1024);
 
-                @Override
-                public CompletionStage<?> onBinary(WebSocket webSocket,
-                                                   ByteBuffer message,
-                                                   boolean last) {
-                    System.out.printf("onBinary(%s, %s)%n", message, last);
-                    webSocket.request(1);
+            @Override
+            public CompletionStage<?> onBinary(WebSocket webSocket,
+                                               ByteBuffer message,
+                                               boolean last) {
+                System.out.printf("onBinary(%s, %s)%n", message, last);
+                webSocket.request(1);
 
-                    append(message);
-                    if (last) {
-                        binary.flip();
-                        byte[] bytes = new byte[binary.remaining()];
-                        binary.get(bytes);
-                        binary.clear();
-                        processWholeBinary(bytes);
-                    }
-                    return null;
+                append(message);
+                if (last) {
+                    buffer.flip();
+                    byte[] bytes = new byte[buffer.remaining()];
+                    buffer.get(bytes);
+                    buffer.clear();
+                    processWholeBinary(bytes);
                 }
+                return null;
+            }
 
-                private void append(ByteBuffer message) {
-                    if (binary.remaining() < message.remaining()) {
-                        assert message.remaining() > 0;
-                        int cap = (binary.capacity() + message.remaining()) * 2;
-                        ByteBuffer b = ByteBuffer.allocate(cap);
-                        b.put(binary.flip());
-                        binary = b;
-                    }
-                    binary.put(message);
+            private void append(ByteBuffer message) {
+                if (buffer.remaining() < message.remaining()) {
+                    assert message.remaining() > 0;
+                    int cap = (buffer.capacity() + message.remaining()) * 2;
+                    ByteBuffer b = ByteBuffer.allocate(cap);
+                    b.put(buffer.flip());
+                    buffer = b;
                 }
+                buffer.put(message);
+            }
 
-                private void processWholeBinary(byte[] bytes) {
-                    String stringBytes = new String(bytes, StandardCharsets.UTF_8);
-                    System.out.println("processWholeBinary: " + stringBytes);
-                    collectedBytes.add(bytes);
-                }
+            private void processWholeBinary(byte[] bytes) {
+                String stringBytes = new String(bytes, StandardCharsets.UTF_8);
+                System.out.println("processWholeBinary: " + stringBytes);
+                collectedBytes.add(bytes);
+            }
 
-                @Override
-                public CompletionStage<?> onClose(WebSocket webSocket,
-                                                  int statusCode,
-                                                  String reason) {
-                    actual.complete(collectedBytes);
-                    return null;
-                }
+            @Override
+            public CompletionStage<?> onClose(WebSocket webSocket,
+                                              int statusCode,
+                                              String reason) {
+                actual.complete(collectedBytes);
+                return null;
+            }
 
-                @Override
-                public void onError(WebSocket webSocket, Throwable error) {
-                    actual.completeExceptionally(error);
-                }
-            };
+            @Override
+            public void onError(WebSocket webSocket, Throwable error) {
+                actual.completeExceptionally(error);
+            }
+        };
 
-            newHttpClient().newWebSocketBuilder()
-                           .buildAsync(server.getURI(), listener)
-                           .join();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), listener)
+                .join();
 
-            List<byte[]> a = actual.join();
-            System.out.println("joined");
-            assertEquals(a, expected);
-        }
+        List<byte[]> a = actual.join();
+        assertEquals(a, expected);
     }
 
     @Test
@@ -685,55 +365,54 @@
         };
         CompletableFuture<List<String>> actual = new CompletableFuture<>();
 
-        try (DummyWebSocketServer server = Support.serverWithCannedData(binary)) {
-            server.open();
+        server = Support.serverWithCannedData(binary);
+        server.open();
 
-            WebSocket.Listener listener = new WebSocket.Listener() {
+        WebSocket.Listener listener = new WebSocket.Listener() {
 
-                List<String> collectedStrings = new ArrayList<>();
-                StringBuilder text = new StringBuilder();
+            List<String> collectedStrings = new ArrayList<>();
+            StringBuilder text = new StringBuilder();
 
-                @Override
-                public CompletionStage<?> onText(WebSocket webSocket,
-                                                 CharSequence message,
-                                                 boolean last) {
-                    System.out.printf("onText(%s, %s)%n", message, last);
-                    webSocket.request(1);
-                    text.append(message);
-                    if (last) {
-                        String str = text.toString();
-                        text.setLength(0);
-                        processWholeText(str);
-                    }
-                    return null;
+            @Override
+            public CompletionStage<?> onText(WebSocket webSocket,
+                                             CharSequence message,
+                                             boolean last) {
+                System.out.printf("onText(%s, %s)%n", message, last);
+                webSocket.request(1);
+                text.append(message);
+                if (last) {
+                    String str = text.toString();
+                    text.setLength(0);
+                    processWholeText(str);
                 }
+                return null;
+            }
 
-                private void processWholeText(String string) {
-                    System.out.println(string);
-                    collectedStrings.add(string);
-                }
+            private void processWholeText(String string) {
+                System.out.println(string);
+                collectedStrings.add(string);
+            }
 
-                @Override
-                public CompletionStage<?> onClose(WebSocket webSocket,
-                                                  int statusCode,
-                                                  String reason) {
-                    actual.complete(collectedStrings);
-                    return null;
-                }
+            @Override
+            public CompletionStage<?> onClose(WebSocket webSocket,
+                                              int statusCode,
+                                              String reason) {
+                actual.complete(collectedStrings);
+                return null;
+            }
 
-                @Override
-                public void onError(WebSocket webSocket, Throwable error) {
-                    actual.completeExceptionally(error);
-                }
-            };
+            @Override
+            public void onError(WebSocket webSocket, Throwable error) {
+                actual.completeExceptionally(error);
+            }
+        };
 
-            newHttpClient().newWebSocketBuilder()
-                           .buildAsync(server.getURI(), listener)
-                           .join();
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), listener)
+                .join();
 
-            List<String> a = actual.join();
-            assertEquals(a, expected);
-        }
+        List<String> a = actual.join();
+        assertEquals(a, expected);
     }
 
     /*
@@ -765,73 +444,67 @@
         CompletableFuture<List<String>> actual = new CompletableFuture<>();
 
 
-        try (DummyWebSocketServer server = Support.serverWithCannedData(binary)) {
-            server.open();
-
-            WebSocket.Listener listener = new WebSocket.Listener() {
+        server = Support.serverWithCannedData(binary);
+        server.open();
 
-                List<CharSequence> parts = new ArrayList<>();
-                /*
-                 * A CompletableFuture which will complete once the current
-                 * message has been fully assembled. Until then the listener
-                 * returns this instance for every call.
-                 */
-                CompletableFuture<?> currentCf = new CompletableFuture<>();
-                List<String> collected = new ArrayList<>();
+        WebSocket.Listener listener = new WebSocket.Listener() {
 
-                @Override
-                public CompletionStage<?> onText(WebSocket webSocket,
-                                                 CharSequence message,
-                                                 boolean last) {
-                    parts.add(message);
-                    if (!last) {
-                        webSocket.request(1);
-                    } else {
-                        this.currentCf.thenRun(() -> webSocket.request(1));
-                        CompletableFuture<?> refCf = this.currentCf;
-                        processWholeMessage(new ArrayList<>(parts), refCf);
-                        currentCf = new CompletableFuture<>();
-                        parts.clear();
-                        return refCf;
-                    }
-                    return currentCf;
-                }
+            List<CharSequence> parts = new ArrayList<>();
+            /*
+             * A CompletableFuture which will complete once the current
+             * message has been fully assembled. Until then the listener
+             * returns this instance for every call.
+             */
+            CompletableFuture<?> currentCf = new CompletableFuture<>();
+            List<String> collected = new ArrayList<>();
 
-                @Override
-                public CompletionStage<?> onClose(WebSocket webSocket,
-                                                  int statusCode,
-                                                  String reason) {
-                    actual.complete(collected);
-                    return null;
+            @Override
+            public CompletionStage<?> onText(WebSocket webSocket,
+                                             CharSequence message,
+                                             boolean last) {
+                parts.add(message);
+                if (!last) {
+                    webSocket.request(1);
+                } else {
+                    this.currentCf.thenRun(() -> webSocket.request(1));
+                    CompletableFuture<?> refCf = this.currentCf;
+                    processWholeMessage(new ArrayList<>(parts), refCf);
+                    currentCf = new CompletableFuture<>();
+                    parts.clear();
+                    return refCf;
                 }
-
-                @Override
-                public void onError(WebSocket webSocket, Throwable error) {
-                    actual.completeExceptionally(error);
-                }
+                return currentCf;
+            }
 
-                public void processWholeMessage(List<CharSequence> data,
-                                                CompletableFuture<?> cf) {
-                    StringBuilder b = new StringBuilder();
-                    data.forEach(b::append);
-                    String s = b.toString();
-                    System.out.println(s);
-                    cf.complete(null);
-                    collected.add(s);
-                }
-            };
+            @Override
+            public CompletionStage<?> onClose(WebSocket webSocket,
+                                              int statusCode,
+                                              String reason) {
+                actual.complete(collected);
+                return null;
+            }
+
+            @Override
+            public void onError(WebSocket webSocket, Throwable error) {
+                actual.completeExceptionally(error);
+            }
 
-            newHttpClient().newWebSocketBuilder()
-                           .buildAsync(server.getURI(), listener)
-                           .join();
+            public void processWholeMessage(List<CharSequence> data,
+                                            CompletableFuture<?> cf) {
+                StringBuilder b = new StringBuilder();
+                data.forEach(b::append);
+                String s = b.toString();
+                System.out.println(s);
+                cf.complete(null);
+                collected.add(s);
+            }
+        };
 
-            List<String> a = actual.join();
-            assertEquals(a, expected);
-        }
-    }
+        webSocket = newHttpClient().newWebSocketBuilder()
+                .buildAsync(server.getURI(), listener)
+                .join();
 
-    @DataProvider(name = "booleans")
-    public Object[][] booleans() {
-        return new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}};
+        List<String> a = actual.join();
+        assertEquals(a, expected);
     }
 }