use of java.util.concurrent.Flow.Subscriber in project helidon by oracle.
the class MultiPartDecoderTest method testPartContentSubscriberThrottling.
@Test
public void testPartContentSubscriberThrottling() {
String boundary = "boundary";
final byte[] chunk1 = ("--" + boundary + "\n" + "Content-Id: part1\n" + "\n" + "body 1.aaaa\n").getBytes();
final byte[] chunk2 = "body 1.bbbb\n".getBytes();
final byte[] chunk3 = ("body 1.cccc\n" + "--" + boundary + "\n" + "Content-Id: part2\n" + "\n" + "This is the 2nd").getBytes();
final byte[] chunk4 = ("body.\n" + "--" + boundary + "--").getBytes();
final CountDownLatch latch = new CountDownLatch(3);
Consumer<BodyPart> consumer = (part) -> {
latch.countDown();
if (latch.getCount() == 2) {
assertThat(part.headers().values("Content-Id"), hasItems("part1"));
}
part.content().subscribe(new Subscriber<DataChunk>() {
@Override
public void onSubscribe(Subscription subscription) {
subscription.request(1);
}
@Override
public void onNext(DataChunk item) {
latch.countDown();
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
});
};
BodyPartSubscriber testSubscriber = new BodyPartSubscriber(SUBSCRIBER_TYPE.ONE_BY_ONE, consumer);
partsPublisher(boundary, List.of(chunk1, chunk2, chunk3, chunk4)).subscribe(testSubscriber);
waitOnLatchNegative(latch, "the 2nd part should not be processed");
assertThat(latch.getCount(), is(equalTo(1L)));
try {
testSubscriber.complete.orTimeout(200, TimeUnit.MILLISECONDS).join();
throw new IllegalStateException("Not expecting to make progress, unless the part is consumed");
} catch (CompletionException e) {
Throwable error = e.getCause();
// This is the expected outcome - the testSubcriber is not making progress
assertThat(error.getClass(), is(equalTo(TimeoutException.class)));
}
}
use of java.util.concurrent.Flow.Subscriber in project helidon by oracle.
the class MultiPartDecoderTest method testContentAcrossChunksAsyncRequest.
@Test
public void testContentAcrossChunksAsyncRequest() {
String boundary = "boundary";
final byte[] chunk1 = ("--" + boundary + "\n" + "Content-Id: part1\n" + "\n" + "thi").getBytes();
final byte[] chunk11 = ("s-is-the-1st-slice-of-the-body\n").getBytes();
final byte[] chunk12 = ("t").getBytes();
final byte[] chunk2 = ("his-is-the-2nd-slice-of-the-body\n" + "--" + boundary + "--").getBytes();
final CountDownLatch latch = new CountDownLatch(2);
Consumer<BodyPart> consumer = (part) -> {
latch.countDown();
assertThat(part.headers().values("Content-Id"), hasItems("part1"));
DataChunkSubscriber subscriber = new DataChunkSubscriber();
part.content().subscribe(subscriber);
subscriber.content().thenAccept(body -> {
assertThat(body, is(equalTo("this-is-the-1st-slice-of-the-body\n" + "this-is-the-2nd-slice-of-the-body")));
}).exceptionally((ex) -> {
System.out.println("UH-OH... " + ex);
return null;
}).thenAccept((_i) -> {
latch.countDown();
});
};
BodyPartSubscriber testSubscriber = new BodyPartSubscriber(SUBSCRIBER_TYPE.ONE_BY_ONE, consumer);
partsPublisher(boundary, List.of(chunk1, chunk11, chunk12, chunk2)).subscribe(testSubscriber);
try {
boolean b = testSubscriber.complete.orTimeout(200, TimeUnit.MILLISECONDS).join();
assertThat(b, is(equalTo(true)));
} catch (CompletionException error) {
assertThat(error, is(nullValue()));
}
waitOnLatch(latch);
}
use of java.util.concurrent.Flow.Subscriber in project helidon by oracle.
the class MultiPartDecoderTest method testMultipleChunksBeforeContent.
@Test
public void testMultipleChunksBeforeContent() {
String boundary = "boundary";
final byte[] chunk1 = ("--" + boundary + "\n" + "Content-Id: part1\n").getBytes();
final byte[] chunk2 = "Content-Type: text/plain\n".getBytes();
final byte[] chunk3 = "Set-Cookie: bob=alice\n".getBytes();
final byte[] chunk4 = "Set-Cookie: foo=bar\n".getBytes();
final byte[] chunk5 = ("\n" + "body 1\n" + "--" + boundary + "--").getBytes();
final CountDownLatch latch = new CountDownLatch(2);
Consumer<BodyPart> consumer = (part) -> {
latch.countDown();
assertThat(part.headers().values("Content-Id"), hasItems("part1"));
assertThat(part.headers().values("Content-Type"), hasItems("text/plain"));
assertThat(part.headers().values("Set-Cookie"), hasItems("bob=alice", "foo=bar"));
DataChunkSubscriber subscriber = new DataChunkSubscriber();
part.content().subscribe(subscriber);
subscriber.content().thenAccept(body -> {
latch.countDown();
assertThat(body, is(equalTo("body 1")));
});
};
BodyPartSubscriber testSubscriber = new BodyPartSubscriber(SUBSCRIBER_TYPE.INFINITE, consumer);
partsPublisher(boundary, List.of(chunk1, chunk2, chunk3, chunk4, chunk5)).subscribe(testSubscriber);
try {
boolean b = testSubscriber.complete.orTimeout(200, TimeUnit.MILLISECONDS).join();
assertThat(b, is(equalTo(true)));
} catch (CompletionException error) {
assertThat(error, is(nullValue()));
}
waitOnLatch(latch);
}
use of java.util.concurrent.Flow.Subscriber in project helidon by oracle.
the class ContextLifeCycleTest method testContextReactive.
@Test
void testContextReactive() {
Handler handler = (req, res) -> {
String cid = req.context().id();
req.content().subscribe(new Subscriber<>() {
@Override
public void onSubscribe(Subscription subscription) {
subscription.request(Long.MAX_VALUE);
}
@Override
public void onNext(DataChunk item) {
item.release();
if (!cid.equals(contextId())) {
throw new IllegalStateException("Context invalid");
}
}
@Override
public void onError(Throwable throwable) {
res.send(throwable);
}
@Override
public void onComplete() {
if (!cid.equals(contextId())) {
res.send(new IllegalStateException("Context invalid"));
} else {
res.send();
}
}
});
};
WebServer webServer = WebServer.builder(Routing.builder().post(handler)).build().start().await(10, TimeUnit.SECONDS);
ResponseStatus responseStatus = WebClient.builder().baseUri("http://localhost:" + webServer.port()).build().post().submit("some-payload").map(WebClientResponse::status).onTerminate(webServer::shutdown).await(10, TimeUnit.SECONDS);
assertThat(responseStatus.code(), is(200));
}
use of java.util.concurrent.Flow.Subscriber in project helidon by oracle.
the class RequestContentTest method multiThreadingFilterAndReaderTest.
@SuppressWarnings("unchecked")
@Test
public void multiThreadingFilterAndReaderTest() throws Exception {
CountDownLatch subscribedLatch = new CountDownLatch(1);
SubmissionPublisher<DataChunk> publisher = new SubmissionPublisher<>(Runnable::run, 10);
ForkJoinPool.commonPool().submit(() -> {
try {
if (!subscribedLatch.await(10, TimeUnit.SECONDS)) {
fail("Subscriber didn't subscribe in timely manner!");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted!", e);
}
publisher.submit(DataChunk.create("first".getBytes()));
publisher.submit(DataChunk.create("second".getBytes()));
publisher.submit(DataChunk.create("third".getBytes()));
publisher.close();
});
Request request = requestTestStub(Multi.create(publisher));
request.content().registerFilter(originalPublisher -> subscriberDelegate -> originalPublisher.subscribe(new Subscriber<DataChunk>() {
@Override
public void onSubscribe(Subscription subscription) {
subscriberDelegate.onSubscribe(subscription);
subscribedLatch.countDown();
}
@Override
public void onNext(DataChunk item) {
// mapping the on next call only
subscriberDelegate.onNext(DataChunk.create(requestChunkAsString(item).toUpperCase().getBytes()));
}
@Override
public void onError(Throwable throwable) {
subscriberDelegate.onError(throwable);
}
@Override
public void onComplete() {
subscriberDelegate.onComplete();
}
}));
request.content().registerReader(Iterable.class, (publisher1, clazz) -> {
fail("Iterable reader should have not been used!");
throw new IllegalStateException("unreachable code");
});
request.content().registerReader(ArrayList.class, (publisher1, clazz) -> {
fail("ArrayList reader should have not been used!");
throw new IllegalStateException("unreachable code");
});
request.content().registerReader(List.class, (publisher1, clazz) -> {
CompletableFuture<List> future = new CompletableFuture<>();
List<String> list = new CopyOnWriteArrayList<>();
publisher1.subscribe(new Subscriber<DataChunk>() {
@Override
public void onSubscribe(Subscription subscription) {
subscription.request(Long.MAX_VALUE);
subscribedLatch.countDown();
}
@Override
public void onNext(DataChunk item) {
list.add(TestUtils.requestChunkAsString(item));
}
@Override
public void onError(Throwable throwable) {
fail("Received an exception: " + throwable.getMessage());
}
@Override
public void onComplete() {
future.complete(list);
}
});
return future;
});
List<String> result = (List<String>) request.content().as(List.class).toCompletableFuture().get(10, TimeUnit.SECONDS);
assertThat(result, hasItems(is("FIRST"), is("SECOND"), is("THIRD")));
}
Aggregations