test/jdk/java/net/httpclient/websocket/WebSocketTextTest.java
branchhttp-client-branch
changeset 56263 4933a477d628
child 56304 065641767a75
equal deleted inserted replaced
56262:d818a6a8295a 56263:4933a477d628
       
     1 /*
       
     2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import org.testng.annotations.DataProvider;
       
    25 import org.testng.annotations.Test;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.net.http.WebSocket;
       
    29 import java.nio.ByteBuffer;
       
    30 import java.nio.charset.StandardCharsets;
       
    31 import java.util.ArrayList;
       
    32 import java.util.List;
       
    33 import java.util.Random;
       
    34 
       
    35 import static java.net.http.HttpClient.newHttpClient;
       
    36 import static org.testng.Assert.assertEquals;
       
    37 import static org.testng.Assert.assertTrue;
       
    38 
       
    39 /*
       
    40  * @test
       
    41  * @bug 8159053
       
    42  *
       
    43  *
       
    44  * @run testng/othervm
       
    45  *      -Djdk.httpclient.websocket.writeBufferSize=1024
       
    46  *      -Djdk.httpclient.websocket.intermediateBufferSize=2048 WebSocketTextTest
       
    47  */
       
    48 public class WebSocketTextTest {
       
    49 
       
    50     private final static Random random;
       
    51     static {
       
    52         long seed = System.currentTimeMillis();
       
    53         System.out.println("seed=" + seed);
       
    54         random = new Random(seed);
       
    55     }
       
    56 
       
    57 // * @run testng/othervm
       
    58 // *      -Djdk.httpclient.websocket.writeBufferSize=16
       
    59 // *      -Djdk.httpclient.sendBufferSize=32 WebSocketTextTest
       
    60 
       
    61 
       
    62 
       
    63     // FIXME ensure subsequent (sendText/Binary, false) only CONTINUATIONs
       
    64 
       
    65     @Test(dataProvider = "binary")
       
    66     public void binary(ByteBuffer expected) throws IOException, InterruptedException {
       
    67         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
       
    68             server.open();
       
    69             WebSocket ws = newHttpClient()
       
    70                     .newWebSocketBuilder()
       
    71                     .buildAsync(server.getURI(), new WebSocket.Listener() { })
       
    72                     .join();
       
    73             ws.sendBinary(expected.duplicate(), true).join();
       
    74             ws.abort();
       
    75             ByteBuffer data = server.read();
       
    76             List<Frame> frames = readFrames(data);
       
    77             assertEquals(frames.size(), 1);
       
    78             Frame f = frames.get(0);
       
    79             assertTrue(f.last);
       
    80             assertEquals(f.opcode, Frame.Opcode.BINARY);
       
    81             assertEquals(f.data, expected);
       
    82         }
       
    83     }
       
    84 
       
    85     private static List<Frame> readFrames(ByteBuffer src) {
       
    86         List<Frame> frames = new ArrayList<>();
       
    87         Frame.Consumer consumer = new Frame.Consumer() {
       
    88 
       
    89             ByteBuffer data;
       
    90             Frame.Opcode opcode;
       
    91             Frame.Masker masker = new Frame.Masker();
       
    92             boolean last;
       
    93 
       
    94             @Override
       
    95             public void fin(boolean value) {
       
    96                 last = value;
       
    97             }
       
    98 
       
    99             @Override
       
   100             public void rsv1(boolean value) {
       
   101                 if (value) {
       
   102                     throw new AssertionError();
       
   103                 }
       
   104             }
       
   105 
       
   106             @Override
       
   107             public void rsv2(boolean value) {
       
   108                 if (value) {
       
   109                     throw new AssertionError();
       
   110                 }
       
   111             }
       
   112 
       
   113             @Override
       
   114             public void rsv3(boolean value) {
       
   115                 if (value) {
       
   116                     throw new AssertionError();
       
   117                 }
       
   118             }
       
   119 
       
   120             @Override
       
   121             public void opcode(Frame.Opcode value) {
       
   122                 opcode = value;
       
   123             }
       
   124 
       
   125             @Override
       
   126             public void mask(boolean value) {
       
   127                 if (!value) { // Frames from the client MUST be masked
       
   128                     throw new AssertionError();
       
   129                 }
       
   130             }
       
   131 
       
   132             @Override
       
   133             public void payloadLen(long value) {
       
   134                 data = ByteBuffer.allocate((int) value);
       
   135             }
       
   136 
       
   137             @Override
       
   138             public void maskingKey(int value) {
       
   139                 masker.mask(value);
       
   140             }
       
   141 
       
   142             @Override
       
   143             public void payloadData(ByteBuffer data) {
       
   144                 masker.transferMasking(data, this.data);
       
   145             }
       
   146 
       
   147             @Override
       
   148             public void endFrame() {
       
   149                 frames.add(new Frame(opcode, this.data.flip(), last));
       
   150             }
       
   151         };
       
   152 
       
   153         Frame.Reader r = new Frame.Reader();
       
   154         while (src.hasRemaining()) {
       
   155             r.readFrame(src, consumer);
       
   156         }
       
   157         return frames;
       
   158     }
       
   159 
       
   160     @Test(dataProvider = "pingPong")
       
   161     public void ping(ByteBuffer expected) throws Exception {
       
   162         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
       
   163             server.open();
       
   164             WebSocket ws = newHttpClient()
       
   165                     .newWebSocketBuilder()
       
   166                     .buildAsync(server.getURI(), new WebSocket.Listener() { })
       
   167                     .join();
       
   168             ws.sendPing(expected.duplicate()).join();
       
   169             ws.abort();
       
   170             ByteBuffer data = server.read();
       
   171             List<Frame> frames = readFrames(data);
       
   172             assertEquals(frames.size(), 1);
       
   173             Frame f = frames.get(0);
       
   174             assertEquals(f.opcode, Frame.Opcode.PING);
       
   175             ByteBuffer actual = ByteBuffer.allocate(expected.remaining());
       
   176             actual.put(f.data);
       
   177             actual.flip();
       
   178             assertEquals(actual, expected);
       
   179         }
       
   180     }
       
   181 
       
   182     @Test(dataProvider = "pingPong")
       
   183     public void pong(ByteBuffer expected) throws Exception {
       
   184         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
       
   185             server.open();
       
   186             WebSocket ws = newHttpClient()
       
   187                     .newWebSocketBuilder()
       
   188                     .buildAsync(server.getURI(), new WebSocket.Listener() { })
       
   189                     .join();
       
   190             ws.sendPong(expected.duplicate()).join();
       
   191             ws.abort();
       
   192             ByteBuffer data = server.read();
       
   193             List<Frame> frames = readFrames(data);
       
   194             assertEquals(frames.size(), 1);
       
   195             Frame f = frames.get(0);
       
   196             assertEquals(f.opcode, Frame.Opcode.PONG);
       
   197             ByteBuffer actual = ByteBuffer.allocate(expected.remaining());
       
   198             actual.put(f.data);
       
   199             actual.flip();
       
   200             assertEquals(actual, expected);
       
   201         }
       
   202     }
       
   203 
       
   204     @Test(dataProvider = "close")
       
   205     public void close(int statusCode, String reason) throws Exception {
       
   206         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
       
   207             server.open();
       
   208             WebSocket ws = newHttpClient()
       
   209                     .newWebSocketBuilder()
       
   210                     .buildAsync(server.getURI(), new WebSocket.Listener() { })
       
   211                     .join();
       
   212             ws.sendClose(statusCode, reason).join();
       
   213             ws.abort();
       
   214             ByteBuffer data = server.read();
       
   215             List<Frame> frames = readFrames(data);
       
   216             assertEquals(frames.size(), 1);
       
   217             Frame f = frames.get(0);
       
   218             assertEquals(f.opcode, Frame.Opcode.CLOSE);
       
   219             ByteBuffer actual = ByteBuffer.allocate(Frame.MAX_CONTROL_FRAME_PAYLOAD_SIZE);
       
   220             actual.put(f.data);
       
   221             actual.flip();
       
   222             assertEquals(actual.getChar(), statusCode);
       
   223             assertEquals(StandardCharsets.UTF_8.decode(actual).toString(), reason);
       
   224         }
       
   225     }
       
   226 
       
   227     @Test(dataProvider = "text")
       
   228     public void text(String expected) throws Exception {
       
   229         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
       
   230             server.open();
       
   231             WebSocket ws = newHttpClient()
       
   232                     .newWebSocketBuilder()
       
   233                     .buildAsync(server.getURI(), new WebSocket.Listener() { })
       
   234                     .join();
       
   235             ws.sendText(expected, true).join();
       
   236             ws.abort();
       
   237             ByteBuffer data = server.read();
       
   238             List<Frame> frames = readFrames(data);
       
   239 
       
   240             int maxBytes = (int) StandardCharsets.UTF_8.newEncoder().maxBytesPerChar() * expected.length();
       
   241             ByteBuffer actual = ByteBuffer.allocate(maxBytes);
       
   242             frames.stream().forEachOrdered(f -> actual.put(f.data));
       
   243             actual.flip();
       
   244             assertEquals(StandardCharsets.UTF_8.decode(actual).toString(), expected);
       
   245         }
       
   246     }
       
   247 
       
   248     @DataProvider(name = "pingPong")
       
   249     public Object[][] pingPongSizes() {
       
   250         return new Object[][]{
       
   251                 {bytes(  0)},
       
   252                 {bytes(  1)},
       
   253                 {bytes( 63)},
       
   254                 {bytes(125)},
       
   255         };
       
   256     }
       
   257 
       
   258     @DataProvider(name = "close")
       
   259     public Object[][] closeArguments() {
       
   260         return new Object[][]{
       
   261                 {WebSocket.NORMAL_CLOSURE, utf8String( 0)},
       
   262                 {WebSocket.NORMAL_CLOSURE, utf8String( 1)},
       
   263                 // 123 / 3 = max reason bytes / max bytes per char
       
   264                 {WebSocket.NORMAL_CLOSURE, utf8String(41)},
       
   265         };
       
   266     }
       
   267 
       
   268     private static String utf8String(int n) {
       
   269         char[] abc = {
       
   270                 // -- English Alphabet (26 characters, 1 byte per char) --
       
   271                 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
       
   272                 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
       
   273                 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
       
   274                 0x0059, 0x005A,
       
   275                 // -- Russian Alphabet (33 characters, 2 bytes per char) --
       
   276                 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416,
       
   277                 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
       
   278                 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426,
       
   279                 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E,
       
   280                 0x042F,
       
   281                 // -- Hiragana base characters (46 characters, 3 bytes per char) --
       
   282                 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x304B, 0x304D, 0x304F,
       
   283                 0x3051, 0x3053, 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, 0x305F,
       
   284                 0x3061, 0x3064, 0x3066, 0x3068, 0x306A, 0x306B, 0x306C, 0x306D,
       
   285                 0x306E, 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, 0x307E, 0x307F,
       
   286                 0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x308A,
       
   287                 0x308B, 0x308C, 0x308D, 0x308F, 0x3092, 0x3093,
       
   288         };
       
   289 
       
   290         assert new String(abc).getBytes(StandardCharsets.UTF_8).length > abc.length;
       
   291 
       
   292         StringBuilder str = new StringBuilder(n);
       
   293         random.ints(0, abc.length).limit(n).forEach(i -> str.append(abc[i]));
       
   294         return str.toString();
       
   295     }
       
   296 
       
   297     @DataProvider(name = "text")
       
   298     public Object[][] texts() {
       
   299         return new Object[][]{
       
   300                 {utf8String(   0)},
       
   301                 {utf8String(1024)},
       
   302         };
       
   303     }
       
   304 
       
   305     @DataProvider(name = "binary")
       
   306     public Object[][] binary() {
       
   307         return new Object[][]{
       
   308                 {bytes(   0)},
       
   309                 {bytes(1024)},
       
   310         };
       
   311     }
       
   312 
       
   313     private static ByteBuffer bytes(int n) {
       
   314         byte[] array = new byte[n];
       
   315         random.nextBytes(array);
       
   316         return ByteBuffer.wrap(array);
       
   317     }
       
   318 }