diff options
Diffstat (limited to 'jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java')
-rw-r--r-- | jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java | 184 |
1 files changed, 182 insertions, 2 deletions
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index 1f68283fcf..405e6d8d56 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.channels.WritePendingException; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -263,7 +264,7 @@ public class HTTP2Test extends AbstractTest } }); - Thread.sleep(1000); + sleep(1000); server.stop(); @@ -285,7 +286,7 @@ public class HTTP2Test extends AbstractTest newClient(new Session.Listener.Adapter()); - Thread.sleep(1000); + sleep(1000); client.stop(); @@ -416,4 +417,183 @@ public class HTTP2Test extends AbstractTest Assert.assertTrue(exchangeLatch2.await(5, TimeUnit.SECONDS)); Assert.assertEquals(0, session.getStreams().size()); } + + @Test + public void testInvalidAPIUsageOnClient() throws Exception + { + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + Callback.Completable completable = new Callback.Completable(); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); + stream.headers(new HeadersFrame(stream.getId(), response, null, false), completable); + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + { + completable.thenRun(() -> + { + DataFrame endFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true); + stream.data(endFrame, Callback.NOOP); + }); + } + } + }; + } + }); + + Session session = newClient(new Session.Listener.Adapter()); + + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame frame = new HeadersFrame(metaData, null, false); + Promise.Completable<Stream> completable = new Promise.Completable<>(); + CountDownLatch completeLatch = new CountDownLatch(2); + session.newStream(frame, completable, new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + completeLatch.countDown(); + } + }); + Stream stream = completable.get(5, TimeUnit.SECONDS); + + long sleep = 1000; + DataFrame data1 = new DataFrame(stream.getId(), ByteBuffer.allocate(1024), false) + { + @Override + public ByteBuffer getData() + { + sleep(2 * sleep); + return super.getData(); + } + }; + DataFrame data2 = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true); + + new Thread(() -> + { + // The first data() call is legal, but slow. + stream.data(data1, new Callback() + { + @Override + public void succeeded() + { + stream.data(data2, NOOP); + } + }); + }).start(); + + // Wait for the first data() call to happen. + sleep(sleep); + + // This data call is illegal because it does not + // wait for the previous callback to complete. + stream.data(data2, new Callback() + { + @Override + public void failed(Throwable x) + { + if (x instanceof WritePendingException) + { + // Expected. + completeLatch.countDown(); + } + } + }); + + Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testInvalidAPIUsageOnServer() throws Exception + { + long sleep = 1000; + CountDownLatch completeLatch = new CountDownLatch(2); + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); + DataFrame dataFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true); + // The call to headers() is legal, but slow. + new Thread(() -> + { + stream.headers(new HeadersFrame(stream.getId(), response, null, false) + { + @Override + public MetaData getMetaData() + { + sleep(2 * sleep); + return super.getMetaData(); + } + }, new Callback() + { + @Override + public void succeeded() + { + stream.data(dataFrame, NOOP); + } + }); + }).start(); + + // Wait for the headers() call to happen. + sleep(sleep); + + // This data call is illegal because it does not + // wait for the previous callback to complete. + stream.data(dataFrame, new Callback() + { + @Override + public void failed(Throwable x) + { + if (x instanceof WritePendingException) + { + // Expected. + completeLatch.countDown(); + } + } + }); + + return null; + } + }); + + Session session = newClient(new Session.Listener.Adapter()); + + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame frame = new HeadersFrame(metaData, null, true); + session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + completeLatch.countDown(); + } + }); + + Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); + } + + private static void sleep(long time) + { + try + { + Thread.sleep(time); + } + catch (InterruptedException x) + { + throw new RuntimeException(); + } + } } |