test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/BinaryPrimitivesTest.java
branchhttp-client-branch
changeset 56092 fd85b2bf2b0d
parent 56089 42208b2f224e
child 56369 24a8fafec3ff
equal deleted inserted replaced
56091:aedd6133e7a0 56092:fd85b2bf2b0d
       
     1 /*
       
     2  * Copyright (c) 2014, 2017, 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 package jdk.internal.net.http.hpack;
       
    24 
       
    25 import org.testng.annotations.Test;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.io.UncheckedIOException;
       
    29 import java.nio.ByteBuffer;
       
    30 import java.nio.CharBuffer;
       
    31 import java.nio.charset.StandardCharsets;
       
    32 import java.util.ArrayList;
       
    33 import java.util.List;
       
    34 import java.util.Random;
       
    35 
       
    36 import static org.testng.Assert.assertEquals;
       
    37 import static org.testng.Assert.fail;
       
    38 import static jdk.internal.net.http.hpack.BuffersTestingKit.*;
       
    39 import static jdk.internal.net.http.hpack.TestHelper.newRandom;
       
    40 
       
    41 //
       
    42 // Some of the tests below overlap in what they test. This allows to diagnose
       
    43 // bugs quicker and with less pain by simply ruling out common working bits.
       
    44 //
       
    45 public final class BinaryPrimitivesTest {
       
    46 
       
    47     private final Random rnd = newRandom();
       
    48 
       
    49     @Test
       
    50     public void integerRead1() {
       
    51         verifyRead(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5);
       
    52     }
       
    53 
       
    54     @Test
       
    55     public void integerRead2() {
       
    56         verifyRead(bytes(0b00001010), 10, 5);
       
    57     }
       
    58 
       
    59     @Test
       
    60     public void integerRead3() {
       
    61         verifyRead(bytes(0b00101010), 42, 8);
       
    62     }
       
    63 
       
    64     @Test
       
    65     public void integerWrite1() {
       
    66         verifyWrite(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5);
       
    67     }
       
    68 
       
    69     @Test
       
    70     public void integerWrite2() {
       
    71         verifyWrite(bytes(0b00001010), 10, 5);
       
    72     }
       
    73 
       
    74     @Test
       
    75     public void integerWrite3() {
       
    76         verifyWrite(bytes(0b00101010), 42, 8);
       
    77     }
       
    78 
       
    79     //
       
    80     // Since readInteger(x) is the inverse of writeInteger(x), thus:
       
    81     //
       
    82     // for all x: readInteger(writeInteger(x)) == x
       
    83     //
       
    84     @Test
       
    85     public void integerIdentity() throws IOException {
       
    86         final int MAX_VALUE = 1 << 22;
       
    87         int totalCases = 0;
       
    88         int maxFilling = 0;
       
    89         IntegerReader r = new IntegerReader();
       
    90         IntegerWriter w = new IntegerWriter();
       
    91         ByteBuffer buf = ByteBuffer.allocate(8);
       
    92         for (int N = 1; N < 9; N++) {
       
    93             for (int expected = 0; expected <= MAX_VALUE; expected++) {
       
    94                 w.reset().configure(expected, N, 1).write(buf);
       
    95                 buf.flip();
       
    96                 totalCases++;
       
    97                 maxFilling = Math.max(maxFilling, buf.remaining());
       
    98                 r.reset().configure(N).read(buf);
       
    99                 assertEquals(r.get(), expected);
       
   100                 buf.clear();
       
   101             }
       
   102         }
       
   103         System.out.printf("totalCases: %,d, maxFilling: %,d, maxValue: %,d%n",
       
   104                 totalCases, maxFilling, MAX_VALUE);
       
   105     }
       
   106 
       
   107     @Test
       
   108     public void integerReadChunked() {
       
   109         final int NUM_TESTS = 1024;
       
   110         IntegerReader r = new IntegerReader();
       
   111         ByteBuffer bb = ByteBuffer.allocate(8);
       
   112         IntegerWriter w = new IntegerWriter();
       
   113         for (int i = 0; i < NUM_TESTS; i++) {
       
   114             final int N = 1 + rnd.nextInt(8);
       
   115             final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1;
       
   116             w.reset().configure(expected, N, rnd.nextInt()).write(bb);
       
   117             bb.flip();
       
   118 
       
   119             forEachSplit(bb,
       
   120                     (buffers) -> {
       
   121                         Iterable<? extends ByteBuffer> buf = relocateBuffers(injectEmptyBuffers(buffers));
       
   122                         r.configure(N);
       
   123                         for (ByteBuffer b : buf) {
       
   124                             try {
       
   125                                 r.read(b);
       
   126                             } catch (IOException e) {
       
   127                                 throw new UncheckedIOException(e);
       
   128                             }
       
   129                         }
       
   130                         assertEquals(r.get(), expected);
       
   131                         r.reset();
       
   132                     });
       
   133             bb.clear();
       
   134         }
       
   135     }
       
   136 
       
   137     // FIXME: use maxValue in the test
       
   138 
       
   139     @Test
       
   140     // FIXME: tune values for better coverage
       
   141     public void integerWriteChunked() {
       
   142         ByteBuffer bb = ByteBuffer.allocate(6);
       
   143         IntegerWriter w = new IntegerWriter();
       
   144         IntegerReader r = new IntegerReader();
       
   145         for (int i = 0; i < 1024; i++) { // number of tests
       
   146             final int N = 1 + rnd.nextInt(8);
       
   147             final int payload = rnd.nextInt(255);
       
   148             final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1;
       
   149 
       
   150             forEachSplit(bb,
       
   151                     (buffers) -> {
       
   152                         List<ByteBuffer> buf = new ArrayList<>();
       
   153                         relocateBuffers(injectEmptyBuffers(buffers)).forEach(buf::add);
       
   154                         boolean written = false;
       
   155                         w.configure(expected, N, payload); // TODO: test for payload it can be read after written
       
   156                         for (ByteBuffer b : buf) {
       
   157                             int pos = b.position();
       
   158                             written = w.write(b);
       
   159                             b.position(pos);
       
   160                         }
       
   161                         if (!written) {
       
   162                             fail("please increase bb size");
       
   163                         }
       
   164                         try {
       
   165                             r.configure(N).read(concat(buf));
       
   166                         } catch (IOException e) {
       
   167                             throw new UncheckedIOException(e);
       
   168                         }
       
   169                         // TODO: check payload here
       
   170                         assertEquals(r.get(), expected);
       
   171                         w.reset();
       
   172                         r.reset();
       
   173                         bb.clear();
       
   174                     });
       
   175         }
       
   176     }
       
   177 
       
   178 
       
   179     //
       
   180     // Since readString(x) is the inverse of writeString(x), thus:
       
   181     //
       
   182     // for all x: readString(writeString(x)) == x
       
   183     //
       
   184     @Test
       
   185     public void stringIdentity() throws IOException {
       
   186         final int MAX_STRING_LENGTH = 4096;
       
   187         ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); // it takes 6 bytes to encode string length of Integer.MAX_VALUE
       
   188         CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH);
       
   189         StringReader reader = new StringReader();
       
   190         StringWriter writer = new StringWriter();
       
   191         for (int len = 0; len <= MAX_STRING_LENGTH; len++) {
       
   192             for (int i = 0; i < 64; i++) {
       
   193                 // not so much "test in isolation", I know... we're testing .reset() as well
       
   194                 bytes.clear();
       
   195                 chars.clear();
       
   196 
       
   197                 byte[] b = new byte[len];
       
   198                 rnd.nextBytes(b);
       
   199 
       
   200                 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string
       
   201 
       
   202                 boolean written = writer
       
   203                         .configure(CharBuffer.wrap(expected), 0, expected.length(), false)
       
   204                         .write(bytes);
       
   205 
       
   206                 if (!written) {
       
   207                     fail("please increase 'bytes' size");
       
   208                 }
       
   209                 bytes.flip();
       
   210                 reader.read(bytes, chars);
       
   211                 chars.flip();
       
   212                 assertEquals(chars.toString(), expected);
       
   213                 reader.reset();
       
   214                 writer.reset();
       
   215             }
       
   216         }
       
   217     }
       
   218 
       
   219 //    @Test
       
   220 //    public void huffmanStringWriteChunked() {
       
   221 //        fail();
       
   222 //    }
       
   223 //
       
   224 //    @Test
       
   225 //    public void huffmanStringReadChunked() {
       
   226 //        fail();
       
   227 //    }
       
   228 
       
   229     @Test
       
   230     public void stringWriteChunked() {
       
   231         final int MAX_STRING_LENGTH = 8;
       
   232         final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6);
       
   233         final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH);
       
   234         final StringReader reader = new StringReader();
       
   235         final StringWriter writer = new StringWriter();
       
   236         for (int len = 0; len <= MAX_STRING_LENGTH; len++) {
       
   237 
       
   238             byte[] b = new byte[len];
       
   239             rnd.nextBytes(b);
       
   240 
       
   241             String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string
       
   242 
       
   243             forEachSplit(bytes, (buffers) -> {
       
   244                 writer.configure(expected, 0, expected.length(), false);
       
   245                 boolean written = false;
       
   246                 for (ByteBuffer buf : buffers) {
       
   247                     int p0 = buf.position();
       
   248                     written = writer.write(buf);
       
   249                     buf.position(p0);
       
   250                 }
       
   251                 if (!written) {
       
   252                     fail("please increase 'bytes' size");
       
   253                 }
       
   254                 try {
       
   255                     reader.read(concat(buffers), chars);
       
   256                 } catch (IOException e) {
       
   257                     throw new UncheckedIOException(e);
       
   258                 }
       
   259                 chars.flip();
       
   260                 assertEquals(chars.toString(), expected);
       
   261                 reader.reset();
       
   262                 writer.reset();
       
   263                 chars.clear();
       
   264                 bytes.clear();
       
   265             });
       
   266         }
       
   267     }
       
   268 
       
   269     @Test
       
   270     public void stringReadChunked() {
       
   271         final int MAX_STRING_LENGTH = 16;
       
   272         final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6);
       
   273         final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH);
       
   274         final StringReader reader = new StringReader();
       
   275         final StringWriter writer = new StringWriter();
       
   276         for (int len = 0; len <= MAX_STRING_LENGTH; len++) {
       
   277 
       
   278             byte[] b = new byte[len];
       
   279             rnd.nextBytes(b);
       
   280 
       
   281             String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string
       
   282 
       
   283             boolean written = writer
       
   284                     .configure(CharBuffer.wrap(expected), 0, expected.length(), false)
       
   285                     .write(bytes);
       
   286             writer.reset();
       
   287 
       
   288             if (!written) {
       
   289                 fail("please increase 'bytes' size");
       
   290             }
       
   291             bytes.flip();
       
   292 
       
   293             forEachSplit(bytes, (buffers) -> {
       
   294                 for (ByteBuffer buf : buffers) {
       
   295                     int p0 = buf.position();
       
   296                     try {
       
   297                         reader.read(buf, chars);
       
   298                     } catch (IOException e) {
       
   299                         throw new UncheckedIOException(e);
       
   300                     }
       
   301                     buf.position(p0);
       
   302                 }
       
   303                 chars.flip();
       
   304                 assertEquals(chars.toString(), expected);
       
   305                 reader.reset();
       
   306                 chars.clear();
       
   307             });
       
   308 
       
   309             bytes.clear();
       
   310         }
       
   311     }
       
   312 
       
   313 //    @Test
       
   314 //    public void test_Huffman_String_Identity() {
       
   315 //        StringWriter writer = new StringWriter();
       
   316 //        StringReader reader = new StringReader();
       
   317 //        // 256 * 8 gives 2048 bits in case of plain 8 bit coding
       
   318 //        // 256 * 30 gives you 7680 bits or 960 bytes in case of almost
       
   319 //        //          improbable event of 256 30 bits symbols in a row
       
   320 //        ByteBuffer binary = ByteBuffer.allocate(960);
       
   321 //        CharBuffer text = CharBuffer.allocate(960 / 5); // 5 = minimum code length
       
   322 //        for (int len = 0; len < 128; len++) {
       
   323 //            for (int i = 0; i < 256; i++) {
       
   324 //                // not so much "test in isolation", I know...
       
   325 //                binary.clear();
       
   326 //
       
   327 //                byte[] bytes = new byte[len];
       
   328 //                rnd.nextBytes(bytes);
       
   329 //
       
   330 //                String s = new String(bytes, StandardCharsets.ISO_8859_1);
       
   331 //
       
   332 //                writer.write(CharBuffer.wrap(s), binary, true);
       
   333 //                binary.flip();
       
   334 //                reader.read(binary, text);
       
   335 //                text.flip();
       
   336 //                assertEquals(text.toString(), s);
       
   337 //            }
       
   338 //        }
       
   339 //    }
       
   340 
       
   341     // TODO: atomic failures: e.g. readonly/overflow
       
   342 
       
   343     private static byte[] bytes(int... data) {
       
   344         byte[] bytes = new byte[data.length];
       
   345         for (int i = 0; i < data.length; i++) {
       
   346             bytes[i] = (byte) data[i];
       
   347         }
       
   348         return bytes;
       
   349     }
       
   350 
       
   351     private static void verifyRead(byte[] data, int expected, int N) {
       
   352         ByteBuffer buf = ByteBuffer.wrap(data, 0, data.length);
       
   353         IntegerReader reader = new IntegerReader();
       
   354         try {
       
   355             reader.configure(N).read(buf);
       
   356         } catch (IOException e) {
       
   357             throw new UncheckedIOException(e);
       
   358         }
       
   359         assertEquals(expected, reader.get());
       
   360     }
       
   361 
       
   362     private void verifyWrite(byte[] expected, int data, int N) {
       
   363         IntegerWriter w = new IntegerWriter();
       
   364         ByteBuffer buf = ByteBuffer.allocate(2 * expected.length);
       
   365         w.configure(data, N, 1).write(buf);
       
   366         buf.flip();
       
   367         assertEquals(ByteBuffer.wrap(expected), buf);
       
   368     }
       
   369 }