use of io.servicetalk.concurrent.api.BufferStrategy.Accumulator in project servicetalk by apple.
the class PublisherBufferTest method subscriberThrowsFromOnNext.
@Test
void subscriberThrowsFromOnNext() {
TestPublisher<Integer> tPublisher = new TestPublisher.Builder<Integer>().disableAutoOnSubscribe().build();
TestPublisher<Accumulator<Integer, Integer>> bPublisher = new TestPublisher.Builder<Accumulator<Integer, Integer>>().disableAutoOnSubscribe().build();
TestSubscription tSubscription = new TestSubscription();
TestSubscription bSubscription = new TestSubscription();
AtomicReference<TerminalNotification> terminal = new AtomicReference<>();
AtomicInteger onNextCounter = new AtomicInteger();
toSource(tPublisher.buffer(new TestBufferStrategy(bPublisher, BUFFER_SIZE_HINT))).subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(MAX_VALUE);
}
@Override
public void onNext(@Nullable Integer integer) {
onNextCounter.incrementAndGet();
throw DELIBERATE_EXCEPTION;
}
@Override
public void onError(Throwable t) {
terminal.set(error(t));
}
@Override
public void onComplete() {
terminal.set(complete());
}
});
assertThat(tPublisher.isSubscribed(), is(true));
tPublisher.onSubscribe(tSubscription);
assertThat(bPublisher.isSubscribed(), is(true));
bPublisher.onSubscribe(bSubscription);
assertThat(tSubscription.requested(), is(0L));
assertThat(bSubscription.requested(), is(MAX_VALUE));
bPublisher.onNext(new SumAccumulator());
assertThat((int) tSubscription.requested(), is(BUFFER_SIZE_HINT));
tPublisher.onNext(1);
bPublisher.onNext(new SumAccumulator());
assertThat(onNextCounter.get(), is(1));
assertThat(terminal.get().cause(), is(DELIBERATE_EXCEPTION));
verifyCancelled(tSubscription);
// Verify that further items are ignored
terminal.set(null);
tPublisher.onNext(2);
bPublisher.onNext(new SumAccumulator());
tPublisher.onComplete();
assertThat(onNextCounter.get(), is(1));
assertThat(terminal.get(), is(nullValue()));
}
use of io.servicetalk.concurrent.api.BufferStrategy.Accumulator in project servicetalk by apple.
the class PublisherBufferTest method originalSourceIsRetriedIfSubscriberThrows.
@Test
void originalSourceIsRetriedIfSubscriberThrows() {
TestPublisher<Accumulator<Integer, Integer>> bPublisher = new TestPublisher<>();
DelayedSubscription bSubscription = new DelayedSubscription();
AtomicReference<TerminalNotification> terminal = new AtomicReference<>();
BlockingQueue<Integer> items = new LinkedBlockingDeque<>();
BlockingQueue<Integer> buffers = new LinkedBlockingDeque<>();
AtomicInteger counter = new AtomicInteger();
toSource(defer(() -> from(counter.incrementAndGet())).whenOnNext(items::add).retry((i, t) -> i < 3 && t == DELIBERATE_EXCEPTION).buffer(new TestBufferStrategy(bPublisher, 1))).subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
bSubscription.delayedSubscription(s);
bSubscription.request(1);
}
@Override
public void onNext(@Nullable Integer integer) {
assert integer != null;
buffers.add(integer);
throw DELIBERATE_EXCEPTION;
}
@Override
public void onError(Throwable t) {
terminal.set(error(t));
}
@Override
public void onComplete() {
terminal.set(complete());
}
});
// it will generate a new boundary on each accumulation
bPublisher.onNext(new SumAccumulator(bPublisher));
assertThat(items, hasSize(1));
assertThat(items, contains(1));
assertThat(buffers, hasSize(1));
assertThat(buffers, contains(1));
bSubscription.request(MAX_VALUE);
assertThat(items, hasSize(3));
assertThat(items, contains(1, 2, 3));
assertThat(buffers, hasSize(3));
assertThat(buffers, contains(1, 2, 3));
assertThat(terminal.get().cause(), is(DELIBERATE_EXCEPTION));
}
use of io.servicetalk.concurrent.api.BufferStrategy.Accumulator in project servicetalk by apple.
the class PublisherBufferTest method subscriberThrowsFromOnNextBeforeTermination.
@Test
void subscriberThrowsFromOnNextBeforeTermination() {
TestPublisher<Integer> tPublisher = new TestPublisher<>();
TestPublisher<Accumulator<Integer, Integer>> bPublisher = new TestPublisher<>();
TestSubscription bSubscription = new TestSubscription();
AtomicReference<TerminalNotification> terminal = new AtomicReference<>();
AtomicInteger onNextCounter = new AtomicInteger();
toSource(tPublisher.buffer(new TestBufferStrategy(bPublisher, BUFFER_SIZE_HINT))).subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(MAX_VALUE);
}
@Override
public void onNext(@Nullable Integer integer) {
onNextCounter.incrementAndGet();
throw DELIBERATE_EXCEPTION;
}
@Override
public void onError(Throwable t) {
terminal.set(error(t));
}
@Override
public void onComplete() {
terminal.set(complete());
}
});
assertThat(bPublisher.isSubscribed(), is(true));
bPublisher.onSubscribe(bSubscription);
assertThat(bSubscription.requested(), is(MAX_VALUE));
bPublisher.onNext(new SumAccumulator());
tPublisher.onNext(1);
tPublisher.onComplete();
assertThat(onNextCounter.get(), is(1));
assertThat(terminal.get().cause(), is(DELIBERATE_EXCEPTION));
verifyCancelled(bSubscription);
// Verify that further items are ignored
terminal.set(null);
tPublisher.onNext(2);
bPublisher.onNext(new SumAccumulator());
tPublisher.onComplete();
assertThat(onNextCounter.get(), is(1));
assertThat(terminal.get(), is(nullValue()));
}
use of io.servicetalk.concurrent.api.BufferStrategy.Accumulator in project servicetalk by apple.
the class BufferStrategiesTest method sizeOrDurationConcurrent.
@Test
@Disabled("https://github.com/apple/servicetalk/issues/1259")
void sizeOrDurationConcurrent() throws Exception {
final BlockingQueue<TestCompletable> timers = new LinkedBlockingDeque<>();
final Executor executor = mock(Executor.class);
when(executor.timer(any(Duration.class))).thenAnswer(invocation -> defer(() -> {
TestCompletable timer = new TestCompletable();
timers.add(timer);
return timer;
}));
final int maxBoundaries = 1_000;
final Collection<Integer> items = unmodifiableCollection(range(1, maxBoundaries).toFuture().get());
final List<Integer> receivedFromBoundaries = new ArrayList<>(items.size());
BufferStrategy<Integer, Accumulator<Integer, Iterable<Integer>>, Iterable<Integer>> strategy = forCountOrTime(1, ofDays(1), executor);
CountDownLatch boundariesDone = new CountDownLatch(1);
BlockingQueue<Accumulator<Integer, Iterable<Integer>>> boundaries = new LinkedBlockingQueue<>();
BlockingQueue<Accumulator<Integer, Iterable<Integer>>> boundariesToFinish = new LinkedBlockingQueue<>();
strategy.boundaries().beforeOnNext(boundaries::add).takeAtMost(maxBoundaries).afterFinally(boundariesDone::countDown).ignoreElements().subscribe();
CyclicBarrier accumulateAndTimerStarted = new CyclicBarrier(2);
Future<Object> timersFuture = EXEC.executor().submit(() -> {
accumulateAndTimerStarted.await();
while (boundariesDone.getCount() > 0) {
timers.take().onComplete();
}
return null;
}).toFuture();
Future<Object> accumulateFuture = EXEC.executor().submit(() -> {
accumulateAndTimerStarted.await();
int boundariesReceived = 0;
Iterator<Integer> itemsToPopulate = items.iterator();
while (itemsToPopulate.hasNext()) {
Accumulator<Integer, Iterable<Integer>> boundary = boundaries.take();
if (++boundariesReceived < maxBoundaries) {
boundary.accumulate(itemsToPopulate.next());
} else {
// add all items to the last boundary
do {
boundary.accumulate(itemsToPopulate.next());
} while (itemsToPopulate.hasNext());
}
boundariesToFinish.add(boundary);
}
return null;
}).toFuture();
boundariesDone.await();
timersFuture.get();
accumulateFuture.get();
Accumulator<Integer, Iterable<Integer>> boundary;
while ((boundary = boundariesToFinish.poll()) != null) {
for (Integer item : boundary.finish()) {
receivedFromBoundaries.add(item);
}
}
assertThat("Unexpected items received.", receivedFromBoundaries, contains(items.toArray()));
}
use of io.servicetalk.concurrent.api.BufferStrategy.Accumulator in project servicetalk by apple.
the class BufferStrategiesTest method boundariesEmittedAccordingToDemand.
@Test
void boundariesEmittedAccordingToDemand() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<TerminalNotification> terminated = new AtomicReference<>();
AtomicInteger count = new AtomicInteger();
final BlockingQueue<Throwable> asyncErrors = new LinkedBlockingDeque<>();
toSource(forCountOrTime(2, ofMillis(1)).boundaries()).subscribe(new Subscriber<Accumulator<Object, Iterable<Object>>>() {
private Subscription s;
private int requested;
@Override
public void onSubscribe(final Subscription subscription) {
s = subscription;
requested++;
s.request(1);
}
@Override
public void onNext(@Nullable final Accumulator<Object, Iterable<Object>> accumulator) {
try {
assertThat("Unexpected accumulator", accumulator, is(notNullValue()));
assertThat("Unexpected accumulation result", accumulator.finish(), emptyIterable());
} catch (Throwable t) {
asyncErrors.add(t);
}
count.incrementAndGet();
if (requested++ < 5) {
s.request(1);
} else {
s.cancel();
latch.countDown();
}
}
@Override
public void onError(final Throwable t) {
terminated.set(error(t));
latch.countDown();
}
@Override
public void onComplete() {
terminated.set(complete());
latch.countDown();
}
});
latch.await();
assertThat("Unexpected number of emitted accumulators", count.get(), is(5));
assertThat("Unexpected termination", terminated.get(), is(nullValue()));
assertNoAsyncErrors(asyncErrors);
}
Aggregations