test/jdk/java/net/httpclient/http2/ServerPush.java
branchhttp-client-branch
changeset 56010 782b2f2d1e76
parent 55973 4d9b002587db
child 56034 43b531ed872b
equal deleted inserted replaced
56009:cf8792f51dee 56010:782b2f2d1e76
    28  * @build jdk.testlibrary.SimpleSSLContext
    28  * @build jdk.testlibrary.SimpleSSLContext
    29  * @modules java.base/sun.net.www.http
    29  * @modules java.base/sun.net.www.http
    30  *          jdk.incubator.httpclient/jdk.incubator.http.internal.common
    30  *          jdk.incubator.httpclient/jdk.incubator.http.internal.common
    31  *          jdk.incubator.httpclient/jdk.incubator.http.internal.frame
    31  *          jdk.incubator.httpclient/jdk.incubator.http.internal.frame
    32  *          jdk.incubator.httpclient/jdk.incubator.http.internal.hpack
    32  *          jdk.incubator.httpclient/jdk.incubator.http.internal.hpack
    33  * @run testng/othervm -Djdk.internal.httpclient.hpack.debug=true -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=errors,requests,responses ServerPush
    33  * @run testng/othervm -Djdk.httpclient.HttpClient.log=errors,requests,responses ServerPush
    34  */
    34  */
    35 
    35 
    36 import java.io.*;
    36 import java.io.*;
    37 import java.net.*;
    37 import java.net.*;
       
    38 import java.nio.ByteBuffer;
    38 import java.nio.file.*;
    39 import java.nio.file.*;
    39 import java.nio.file.attribute.*;
       
    40 import jdk.incubator.http.*;
    40 import jdk.incubator.http.*;
    41 import jdk.incubator.http.HttpResponse.MultiSubscriber;
       
    42 import jdk.incubator.http.HttpResponse.BodyHandler;
    41 import jdk.incubator.http.HttpResponse.BodyHandler;
       
    42 import jdk.incubator.http.HttpResponse.BodySubscriber;
       
    43 import jdk.incubator.http.HttpResponse.PushPromiseHandler;
    43 import java.util.*;
    44 import java.util.*;
    44 import java.util.concurrent.*;
    45 import java.util.concurrent.*;
       
    46 import java.util.function.Consumer;
       
    47 import java.util.function.Function;
       
    48 import java.util.function.UnaryOperator;
       
    49 
       
    50 import org.testng.annotations.AfterTest;
       
    51 import org.testng.annotations.BeforeTest;
    45 import org.testng.annotations.Test;
    52 import org.testng.annotations.Test;
       
    53 import static java.nio.charset.StandardCharsets.UTF_8;
       
    54 import static org.testng.Assert.*;
       
    55 
    46 
    56 
    47 public class ServerPush {
    57 public class ServerPush {
    48 
       
    49     static ExecutorService e = Executors.newCachedThreadPool();
       
    50 
    58 
    51     static final int LOOPS = 13;
    59     static final int LOOPS = 13;
    52     static final int FILE_SIZE = 512 * 1024 + 343;
    60     static final int FILE_SIZE = 512 * 1024 + 343;
    53 
    61 
    54     static Path tempFile;
    62     static Path tempFile;
    55 
    63 
       
    64     Http2TestServer server;
       
    65     URI uri;
       
    66 
       
    67     @BeforeTest
       
    68     public void setup() throws Exception {
       
    69         server = new Http2TestServer(false, 0);
       
    70         server.addHandler(new PushHandler(FILE_SIZE, LOOPS), "/");
       
    71         tempFile = TestUtil.getAFile(FILE_SIZE);
       
    72         System.out.println("Using temp file:" + tempFile);
       
    73 
       
    74         System.err.println("Server listening on port " + server.getAddress().getPort());
       
    75         server.start();
       
    76         int port = server.getAddress().getPort();
       
    77         uri = new URI("http://127.0.0.1:" + port + "/foo/a/b/c");
       
    78     }
       
    79 
       
    80     @AfterTest
       
    81     public void teardown() {
       
    82         server.stop();
       
    83     }
       
    84 
       
    85     static final UnaryOperator<HttpResponse<?>>
       
    86             assert200ResponseCode = (response) -> {
       
    87                 assertEquals(response.statusCode(), 200);
       
    88                 return response;
       
    89     };
       
    90 
       
    91     interface Peeker<T> extends UnaryOperator<T> {
       
    92         void peek(T t);
       
    93 
       
    94         default T apply(T t)
       
    95         {
       
    96             peek(t);
       
    97             return t;
       
    98         }
       
    99     }
       
   100 
    56     @Test
   101     @Test
    57     public static void test() throws Exception {
   102     public void testTypeString() throws Exception {
    58         Http2TestServer server = null;
   103         // use multi-level path
    59         final Path dir = Files.createTempDirectory("serverPush");
   104         HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
       
   105 
       
   106         String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
       
   107 
       
   108         // Attempt 2
       
   109         HttpClient client = HttpClient.newBuilder()
       
   110                 .version(HttpClient.Version.HTTP_2)
       
   111                 .build();
       
   112 
       
   113         ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<String>>> results = new ConcurrentHashMap<>();
       
   114 
       
   115 
       
   116         // Example 2 - of(...) building your own Map, everything as a String
       
   117         PushPromiseHandler<String> pph = (initial, pushRequest, acceptor) -> {
       
   118             BodyHandler<String> s = BodyHandler.asString(UTF_8);
       
   119             CompletableFuture<HttpResponse<String>> cf = acceptor.apply(s);
       
   120             results.put(pushRequest, cf);
       
   121         };
       
   122 
       
   123         CompletableFuture<HttpResponse<String>> cf =
       
   124                 client.sendAsync(request, BodyHandler.asString(), pph);
       
   125         cf.join();
       
   126         results.put(request, cf);
       
   127 
       
   128         System.err.println(results.size());
       
   129         Set<HttpRequest> requests = results.keySet();
       
   130 
       
   131         System.err.println("results.size: " + results.size());
       
   132         for (HttpRequest r : requests) {
       
   133             String result = results.get(r).get().body();
       
   134             if (!result.equals(tempFileAsString)) {
       
   135                 System.err.println("Got [" + result + ", expected [" + tempFileAsString + "]");
       
   136             }
       
   137         }
       
   138         if (requests.size() != LOOPS + 1)
       
   139             throw new RuntimeException("Some results missing, expected:" + LOOPS + 1 + ", got:" + results.size());
       
   140     }
       
   141 
       
   142     // --- Path ---
       
   143 
       
   144     static final Path dir = Paths.get(".", "serverPush");
       
   145     static BodyHandler<Path> requestToPath(HttpRequest req) {
       
   146         URI u = req.uri();
       
   147         Path path = Paths.get(dir.toString(), u.getPath());
    60         try {
   148         try {
    61             server = new Http2TestServer(false, 0);
   149             Files.createDirectories(path.getParent());
    62             server.addHandler(new PushHandler(FILE_SIZE, LOOPS), "/");
   150         } catch (IOException ee) {
    63             tempFile = TestUtil.getAFile(FILE_SIZE);
   151             throw new UncheckedIOException(ee);
    64 
   152         }
    65             System.err.println("Server listening on port " + server.getAddress().getPort());
   153         return BodyHandler.asFile(path);
    66             server.start();
   154     };
    67             int port = server.getAddress().getPort();
   155 
    68 
   156     @Test
    69             // use multi-level path
   157     public void testTypePath() throws Exception {
    70             URI uri = new URI("http://127.0.0.1:" + port + "/foo/a/b/c");
   158         HttpClient client = HttpClient.newHttpClient();
    71             HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
   159         HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
    72 
   160 
    73             CompletableFuture<MultiMapResult<Path>> cf =
   161         ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<Path>>> map
    74                 HttpClient.newBuilder().version(HttpClient.Version.HTTP_2)
   162                 = new ConcurrentHashMap<>();
    75                     .executor(e).build().sendAsync(
   163 
    76                         request, MultiSubscriber.asMap((req) -> {
   164         // Example 4 - of(...) building your own Map, everything as a Path
    77                             URI u = req.uri();
   165         PushPromiseHandler<Path> pushPromiseHandler = (initial, pushRequest, acceptor) -> {
    78                             Path path = Paths.get(dir.toString(), u.getPath());
   166             BodyHandler<Path> pp = requestToPath(pushRequest);
    79                             try {
   167             CompletableFuture<HttpResponse<Path>> cf = acceptor.apply(pp);
    80                                 Files.createDirectories(path.getParent());
   168             map.put(pushRequest, cf);
    81                             } catch (IOException ee) {
   169         };
    82                                 throw new UncheckedIOException(ee);
   170 
    83                             }
   171         CompletableFuture<HttpResponse<Path>> cf =
    84                             return Optional.of(BodyHandler.asFile(path));
   172                 client.sendAsync(request, requestToPath(request), pushPromiseHandler);
    85                         }
   173         cf.join();
    86                     ));
   174         map.put(request, cf);
    87             MultiMapResult<Path> results = cf.get();
   175 
    88 
   176         System.err.println("map.size: " + map.size());
    89             //HttpResponse resp = request.response();
   177         for (HttpRequest r : map.keySet()) {
    90             System.err.println(results.size());
   178             Path path = map.get(r).get().body();
    91             Set<HttpRequest> requests = results.keySet();
   179             String fileAsString = new String(Files.readAllBytes(path), UTF_8);
    92 
   180             String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
    93             for (HttpRequest r : requests) {
   181             assertEquals(fileAsString, tempFileAsString);
    94                 URI u = r.uri();
   182         }
    95                 Path result = results.get(r).get().body();
   183         assertEquals(map.size(),  LOOPS + 1);
    96                 System.err.printf("%s -> %s\n", u.toString(), result.toString());
   184     }
    97                 TestUtil.compareFiles(result, tempFile);
   185 
       
   186     // ---  Consumer<byte[]> ---
       
   187 
       
   188     static class ByteArrayConsumer implements Consumer<Optional<byte[]>> {
       
   189         volatile List<byte[]> listByteArrays = new ArrayList<>();
       
   190         volatile byte[] accumulatedBytes;
       
   191 
       
   192         public byte[] getAccumulatedBytes() { return accumulatedBytes; }
       
   193 
       
   194         @Override
       
   195         public void accept(Optional<byte[]> optionalBytes) {
       
   196             assert accumulatedBytes == null;
       
   197             if (!optionalBytes.isPresent()) {
       
   198                 int size = listByteArrays.stream().mapToInt(ba -> ba.length).sum();
       
   199                 ByteBuffer bb = ByteBuffer.allocate(size);
       
   200                 listByteArrays.stream().forEach(ba -> bb.put(ba));
       
   201                 accumulatedBytes = bb.array();
       
   202             } else {
       
   203                 listByteArrays.add(optionalBytes.get());
    98             }
   204             }
    99             if (requests.size() != LOOPS + 1)
   205         }
   100                 throw new RuntimeException("some results missing");
   206     }
   101             System.out.println("TEST OK: sleeping for 5 sec");
   207 
   102             Thread.sleep (5 * 1000);
   208     @Test
   103         } finally {
   209     public void testTypeByteArrayConsumer() throws Exception {
   104             e.shutdownNow();
   210         HttpClient client = HttpClient.newHttpClient();
   105             server.stop();
   211         HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
   106             Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
   212 
   107                 public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
   213         ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<Void>>> resultMap
   108                     dir.toFile().delete();
   214                 = new ConcurrentHashMap<>();
   109                     return FileVisitResult.CONTINUE;
   215         Map<HttpRequest,ByteArrayConsumer> byteArrayConsumerMap
   110                 }
   216                 = new ConcurrentHashMap<>();
   111                 public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
   217 
   112                     path.toFile().delete();
   218         ByteArrayConsumer bac = new ByteArrayConsumer();
   113                     return FileVisitResult.CONTINUE;
   219         byteArrayConsumerMap.put(request, bac);
   114                 }
   220 
   115             });
   221         // Example 5 - withXXX and everything as a consumer of optional byte[]
   116         }
   222         PushPromiseHandler<Void> pushPromiseHandler =
       
   223                 PushPromiseHandler.withPushPromises(pushRequest -> {
       
   224                                                        ByteArrayConsumer bc = new ByteArrayConsumer();
       
   225                                                        byteArrayConsumerMap.put(pushRequest, bc);
       
   226                                                        return BodyHandler.asByteArrayConsumer(bc);
       
   227                                                     },
       
   228                                                     resultMap);
       
   229 
       
   230         CompletableFuture<HttpResponse<Void>> cf =
       
   231                 client.sendAsync(request, BodyHandler.asByteArrayConsumer(bac), pushPromiseHandler);
       
   232         cf.join();
       
   233         resultMap.put(request, cf);
       
   234 
       
   235         System.err.println("map.size: " + resultMap.size());
       
   236         for (HttpRequest r : resultMap.keySet()) {
       
   237             resultMap.get(r).join();
       
   238             byte[] ba = byteArrayConsumerMap.get(r).getAccumulatedBytes();
       
   239             String result = new String(ba, UTF_8);
       
   240             System.out.println("HEGO result=" + result);
       
   241             System.out.println("HEGO result.length=" + result.length());
       
   242             System.err.printf("%s -> %s\n", r.uri().toString(), result);
       
   243             String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
       
   244             System.out.println("HEGO tempFileAsString=" + tempFileAsString);
       
   245             System.out.println("HEGO tempFileAsString.length=" + tempFileAsString.length());
       
   246             assertEquals(result, tempFileAsString);
       
   247         }
       
   248 
       
   249         assertEquals(resultMap.size(), LOOPS + 1);
   117     }
   250     }
   118 }
   251 }