@Test
 public void clientRequestStreamDependencyInHttpMessageFlow() throws Exception {
   setServerLatch(2);
   final String text = "hello world big time data!";
   final ByteBuf content = Unpooled.copiedBuffer(text.getBytes());
   final String text2 = "hello world big time data...number 2!!";
   final ByteBuf content2 = Unpooled.copiedBuffer(text2.getBytes());
   final FullHttpRequest request =
       new DefaultFullHttpRequest(
           HttpVersion.HTTP_1_1, HttpMethod.PUT, "/some/path/resource", content, true);
   final FullHttpMessage request2 =
       new DefaultFullHttpRequest(
           HttpVersion.HTTP_1_1, HttpMethod.PUT, "/some/path/resource2", content2, true);
   try {
     HttpHeaders httpHeaders = request.headers();
     httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
     httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, text.length());
     HttpHeaders httpHeaders2 = request2.headers();
     httpHeaders2.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
     httpHeaders2.set(HttpUtil.ExtensionHeaderNames.STREAM_DEPENDENCY_ID.text(), 3);
     httpHeaders2.set(HttpUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), 123);
     httpHeaders2.set(HttpHeaders.Names.CONTENT_LENGTH, text2.length());
     final Http2Headers http2Headers =
         new DefaultHttp2Headers().method(as("PUT")).path(as("/some/path/resource"));
     final Http2Headers http2Headers2 =
         new DefaultHttp2Headers().method(as("PUT")).path(as("/some/path/resource2"));
     runInChannel(
         clientChannel,
         new Http2Runnable() {
           @Override
           public void run() {
             frameWriter.writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
             frameWriter.writeHeaders(ctxClient(), 5, http2Headers2, 0, false, newPromiseClient());
             frameWriter.writePriority(ctxClient(), 5, 3, (short) 123, true, newPromiseClient());
             frameWriter.writeData(ctxClient(), 3, content.retain(), 0, true, newPromiseClient());
             frameWriter.writeData(ctxClient(), 5, content2.retain(), 0, true, newPromiseClient());
             ctxClient().flush();
           }
         });
     awaitRequests();
     ArgumentCaptor<FullHttpMessage> httpObjectCaptor =
         ArgumentCaptor.forClass(FullHttpMessage.class);
     verify(serverListener, times(2)).messageReceived(httpObjectCaptor.capture());
     capturedRequests = httpObjectCaptor.getAllValues();
     assertEquals(request, capturedRequests.get(0));
     assertEquals(request2, capturedRequests.get(1));
   } finally {
     request.release();
     request2.release();
   }
 }
 @Test
 public void clientRequestMultipleEmptyDataFrames() throws Exception {
   final String text = "";
   final ByteBuf content = Unpooled.copiedBuffer(text.getBytes());
   final FullHttpRequest request =
       new DefaultFullHttpRequest(
           HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/path/resource2", content, true);
   try {
     HttpHeaders httpHeaders = request.headers();
     httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
     httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, text.length());
     final Http2Headers http2Headers =
         new DefaultHttp2Headers().method(as("GET")).path(as("/some/path/resource2"));
     runInChannel(
         clientChannel,
         new Http2Runnable() {
           @Override
           public void run() {
             frameWriter.writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
             frameWriter.writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient());
             frameWriter.writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient());
             frameWriter.writeData(ctxClient(), 3, content.retain(), 0, true, newPromiseClient());
             ctxClient().flush();
           }
         });
     awaitRequests();
     ArgumentCaptor<FullHttpMessage> requestCaptor =
         ArgumentCaptor.forClass(FullHttpMessage.class);
     verify(serverListener).messageReceived(requestCaptor.capture());
     capturedRequests = requestCaptor.getAllValues();
     assertEquals(request, capturedRequests.get(0));
   } finally {
     request.release();
   }
 }
 @Test
 public void clientRequestMultipleHeaders() throws Exception {
   // writeHeaders will implicitly add an END_HEADERS tag each time and so this test does not
   // follow the HTTP
   // message flow. We currently accept this message flow and just add the second headers to the
   // trailing headers.
   final String text = "";
   final ByteBuf content = Unpooled.copiedBuffer(text.getBytes());
   final FullHttpRequest request =
       new DefaultFullHttpRequest(
           HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/path/resource2", content, true);
   try {
     HttpHeaders httpHeaders = request.headers();
     httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
     httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, text.length());
     HttpHeaders trailingHeaders = request.trailingHeaders();
     trailingHeaders.set("FoO", "goo");
     trailingHeaders.set("foO2", "goo2");
     trailingHeaders.add("fOo2", "goo3");
     final Http2Headers http2Headers =
         new DefaultHttp2Headers().method(as("GET")).path(as("/some/path/resource2"));
     final Http2Headers http2Headers2 =
         new DefaultHttp2Headers()
             .set(as("foo"), as("goo"))
             .set(as("foo2"), as("goo2"))
             .add(as("foo2"), as("goo3"));
     runInChannel(
         clientChannel,
         new Http2Runnable() {
           @Override
           public void run() {
             frameWriter.writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
             frameWriter.writeHeaders(ctxClient(), 3, http2Headers2, 0, false, newPromiseClient());
             frameWriter.writeData(ctxClient(), 3, content.retain(), 0, true, newPromiseClient());
             ctxClient().flush();
           }
         });
     awaitRequests();
     ArgumentCaptor<FullHttpMessage> requestCaptor =
         ArgumentCaptor.forClass(FullHttpMessage.class);
     verify(serverListener).messageReceived(requestCaptor.capture());
     capturedRequests = requestCaptor.getAllValues();
     assertEquals(request, capturedRequests.get(0));
   } finally {
     request.release();
   }
 }
 @Test
 public void clientRequestSingleHeaderNoDataFrames() throws Exception {
   final FullHttpRequest request =
       new DefaultFullHttpRequest(
           HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/path/resource2", true);
   try {
     HttpHeaders httpHeaders = request.headers();
     httpHeaders.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "https");
     httpHeaders.set(HttpUtil.ExtensionHeaderNames.AUTHORITY.text(), "example.org");
     httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
     httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, 0);
     final Http2Headers http2Headers =
         new DefaultHttp2Headers()
             .method(as("GET"))
             .scheme(as("https"))
             .authority(as("example.org"))
             .path(as("/some/path/resource2"));
     runInChannel(
         clientChannel,
         new Http2Runnable() {
           @Override
           public void run() {
             frameWriter.writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
             ctxClient().flush();
           }
         });
     awaitRequests();
     ArgumentCaptor<FullHttpMessage> requestCaptor =
         ArgumentCaptor.forClass(FullHttpMessage.class);
     verify(serverListener).messageReceived(requestCaptor.capture());
     capturedRequests = requestCaptor.getAllValues();
     assertEquals(request, capturedRequests.get(0));
   } finally {
     request.release();
   }
 }
  @Test
  public void serverResponseHeaderInformational() throws Exception {
    final FullHttpMessage request =
        new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.PUT, "/info/test", true);
    HttpHeaders httpHeaders = request.headers();
    httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
    httpHeaders.set(HttpHeaders.Names.EXPECT, HttpHeaders.Values.CONTINUE);
    httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, 0);
    final Http2Headers http2Headers =
        new DefaultHttp2Headers()
            .method(as("PUT"))
            .path(as("/info/test"))
            .set(
                as(HttpHeaders.Names.EXPECT.toString()),
                as(HttpHeaders.Values.CONTINUE.toString()));
    final FullHttpMessage response =
        new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
    final String text = "a big payload";
    final ByteBuf payload = Unpooled.copiedBuffer(text.getBytes());
    final FullHttpMessage request2 = request.copy(payload);
    final FullHttpMessage response2 =
        new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);

    try {
      runInChannel(
          clientChannel,
          new Http2Runnable() {
            @Override
            public void run() {
              frameWriter.writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
              ctxClient().flush();
            }
          });
      awaitRequests();
      ArgumentCaptor<FullHttpMessage> requestCaptor =
          ArgumentCaptor.forClass(FullHttpMessage.class);
      verify(serverListener).messageReceived(requestCaptor.capture());
      capturedRequests = requestCaptor.getAllValues();
      assertEquals(request, capturedRequests.get(0));
      cleanupCapturedRequests();
      reset(serverListener);

      httpHeaders = response.headers();
      httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
      httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, 0);
      final Http2Headers http2HeadersResponse = new DefaultHttp2Headers().status(as("100"));
      runInChannel(
          serverConnectedChannel,
          new Http2Runnable() {
            @Override
            public void run() {
              frameWriter.writeHeaders(
                  ctxServer(), 3, http2HeadersResponse, 0, false, newPromiseServer());
              ctxServer().flush();
            }
          });
      awaitResponses();
      ArgumentCaptor<FullHttpMessage> responseCaptor =
          ArgumentCaptor.forClass(FullHttpMessage.class);
      verify(clientListener).messageReceived(responseCaptor.capture());
      capturedResponses = responseCaptor.getAllValues();
      assertEquals(response, capturedResponses.get(0));
      cleanupCapturedResponses();
      reset(clientListener);

      setServerLatch(1);
      httpHeaders = request2.headers();
      httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, text.length());
      httpHeaders.remove(HttpHeaders.Names.EXPECT);
      runInChannel(
          clientChannel,
          new Http2Runnable() {
            @Override
            public void run() {
              frameWriter.writeData(ctxClient(), 3, payload.retain(), 0, true, newPromiseClient());
              ctxClient().flush();
            }
          });
      awaitRequests();
      requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
      verify(serverListener).messageReceived(requestCaptor.capture());
      capturedRequests = requestCaptor.getAllValues();
      assertEquals(request2, capturedRequests.get(0));

      setClientLatch(1);
      httpHeaders = response2.headers();
      httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
      httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, 0);
      final Http2Headers http2HeadersResponse2 = new DefaultHttp2Headers().status(as("200"));
      runInChannel(
          serverConnectedChannel,
          new Http2Runnable() {
            @Override
            public void run() {
              frameWriter.writeHeaders(
                  ctxServer(), 3, http2HeadersResponse2, 0, true, newPromiseServer());
              ctxServer().flush();
            }
          });
      awaitResponses();
      responseCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
      verify(clientListener).messageReceived(responseCaptor.capture());
      capturedResponses = responseCaptor.getAllValues();
      assertEquals(response2, capturedResponses.get(0));
    } finally {
      request.release();
      request2.release();
      response.release();
      response2.release();
    }
  }
  @Test
  public void serverRequestPushPromise() throws Exception {
    setClientLatch(2);
    final String text = "hello world big time data!";
    final ByteBuf content = Unpooled.copiedBuffer(text.getBytes());
    final String text2 = "hello world smaller data?";
    final ByteBuf content2 = Unpooled.copiedBuffer(text2.getBytes());
    final FullHttpMessage response =
        new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content, true);
    final FullHttpMessage response2 =
        new DefaultFullHttpResponse(
            HttpVersion.HTTP_1_1, HttpResponseStatus.CREATED, content2, true);
    final FullHttpMessage request =
        new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/push/test", true);
    try {
      HttpHeaders httpHeaders = response.headers();
      httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
      httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, text.length());
      HttpHeaders httpHeaders2 = response2.headers();
      httpHeaders2.set(HttpUtil.ExtensionHeaderNames.SCHEME.text(), "https");
      httpHeaders2.set(HttpUtil.ExtensionHeaderNames.AUTHORITY.text(), "example.org");
      httpHeaders2.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
      httpHeaders2.set(HttpUtil.ExtensionHeaderNames.STREAM_PROMISE_ID.text(), 3);
      httpHeaders2.set(HttpHeaders.Names.CONTENT_LENGTH, text2.length());

      httpHeaders = request.headers();
      httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
      httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, 0);
      final Http2Headers http2Headers3 =
          new DefaultHttp2Headers().method(as("GET")).path(as("/push/test"));
      runInChannel(
          clientChannel,
          new Http2Runnable() {
            @Override
            public void run() {
              frameWriter.writeHeaders(ctxClient(), 3, http2Headers3, 0, true, newPromiseClient());
              ctxClient().flush();
            }
          });
      awaitRequests();
      ArgumentCaptor<FullHttpMessage> requestCaptor =
          ArgumentCaptor.forClass(FullHttpMessage.class);
      verify(serverListener).messageReceived(requestCaptor.capture());
      capturedRequests = requestCaptor.getAllValues();
      assertEquals(request, capturedRequests.get(0));

      final Http2Headers http2Headers = new DefaultHttp2Headers().status(as("200"));
      final Http2Headers http2Headers2 =
          new DefaultHttp2Headers()
              .status(as("201"))
              .scheme(as("https"))
              .authority(as("example.org"));
      runInChannel(
          serverConnectedChannel,
          new Http2Runnable() {
            @Override
            public void run() {
              frameWriter.writeHeaders(ctxServer(), 3, http2Headers, 0, false, newPromiseServer());
              frameWriter.writePushPromise(ctxServer(), 3, 5, http2Headers2, 0, newPromiseServer());
              frameWriter.writeData(ctxServer(), 3, content.retain(), 0, true, newPromiseServer());
              frameWriter.writeData(ctxServer(), 5, content2.retain(), 0, true, newPromiseServer());
              ctxServer().flush();
            }
          });
      awaitResponses();
      ArgumentCaptor<FullHttpMessage> responseCaptor =
          ArgumentCaptor.forClass(FullHttpMessage.class);
      verify(clientListener, times(2)).messageReceived(responseCaptor.capture());
      capturedResponses = responseCaptor.getAllValues();
      assertEquals(response, capturedResponses.get(0));
      assertEquals(response2, capturedResponses.get(1));
    } finally {
      request.release();
      response.release();
      response2.release();
    }
  }