/** * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.internal.operators.flowable; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import org.junit.*; import org.mockito.*; import org.reactivestreams.*; import io.reactivex.*; import io.reactivex.exceptions.TestException; import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; import io.reactivex.internal.subscriptions.BooleanSubscription; import io.reactivex.plugins.RxJavaPlugins; import io.reactivex.processors.PublishProcessor; import io.reactivex.schedulers.*; import io.reactivex.subscribers.*; public class FlowableBufferTest { private Subscriber<List<String>> observer; private TestScheduler scheduler; private Scheduler.Worker innerScheduler; @Before public void before() { observer = TestHelper.mockSubscriber(); scheduler = new TestScheduler(); innerScheduler = scheduler.createWorker(); } @Test public void testComplete() { Flowable<String> source = Flowable.empty(); Flowable<List<String>> buffered = source.buffer(3, 3); buffered.subscribe(observer); Mockito.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); Mockito.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); Mockito.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testSkipAndCountOverlappingBuffers() { Flowable<String> source = Flowable.unsafeCreate(new Publisher<String>() { @Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(new BooleanSubscription()); observer.onNext("one"); observer.onNext("two"); observer.onNext("three"); observer.onNext("four"); observer.onNext("five"); } }); Flowable<List<String>> buffered = source.buffer(3, 1); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); inOrder.verify(observer, Mockito.times(1)).onNext(list("two", "three", "four")); inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four", "five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.never()).onComplete(); } @Test public void testSkipAndCountGaplessBuffers() { Flowable<String> source = Flowable.just("one", "two", "three", "four", "five"); Flowable<List<String>> buffered = source.buffer(3, 3); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testSkipAndCountBuffersWithGaps() { Flowable<String> source = Flowable.just("one", "two", "three", "four", "five"); Flowable<List<String>> buffered = source.buffer(2, 3); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testTimedAndCount() { Flowable<String> source = Flowable.unsafeCreate(new Publisher<String>() { @Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, "one", 10); push(observer, "two", 90); push(observer, "three", 110); push(observer, "four", 190); push(observer, "five", 210); complete(observer, 250); } }); Flowable<List<String>> buffered = source.buffer(100, TimeUnit.MILLISECONDS, scheduler, 2); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); scheduler.advanceTimeTo(100, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); scheduler.advanceTimeTo(200, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four")); scheduler.advanceTimeTo(300, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testTimed() { Flowable<String> source = Flowable.unsafeCreate(new Publisher<String>() { @Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, "one", 97); push(observer, "two", 98); /** * Changed from 100. Because scheduling the cut to 100ms happens before this * Flowable even runs due how lift works, pushing at 100ms would execute after the * buffer cut. */ push(observer, "three", 99); push(observer, "four", 101); push(observer, "five", 102); complete(observer, 150); } }); Flowable<List<String>> buffered = source.buffer(100, TimeUnit.MILLISECONDS, scheduler); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); scheduler.advanceTimeTo(101, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); scheduler.advanceTimeTo(201, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testFlowableBasedOpenerAndCloser() { Flowable<String> source = Flowable.unsafeCreate(new Publisher<String>() { @Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, "one", 10); push(observer, "two", 60); push(observer, "three", 110); push(observer, "four", 160); push(observer, "five", 210); complete(observer, 500); } }); Flowable<Object> openings = Flowable.unsafeCreate(new Publisher<Object>() { @Override public void subscribe(Subscriber<Object> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, new Object(), 50); push(observer, new Object(), 200); complete(observer, 250); } }); Function<Object, Flowable<Object>> closer = new Function<Object, Flowable<Object>>() { @Override public Flowable<Object> apply(Object opening) { return Flowable.unsafeCreate(new Publisher<Object>() { @Override public void subscribe(Subscriber<? super Object> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, new Object(), 100); complete(observer, 101); } }); } }; Flowable<List<String>> buffered = source.buffer(openings, closer); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("two", "three")); inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testFlowableBasedCloser() { Flowable<String> source = Flowable.unsafeCreate(new Publisher<String>() { @Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, "one", 10); push(observer, "two", 60); push(observer, "three", 110); push(observer, "four", 160); push(observer, "five", 210); complete(observer, 250); } }); Callable<Flowable<Object>> closer = new Callable<Flowable<Object>>() { @Override public Flowable<Object> call() { return Flowable.unsafeCreate(new Publisher<Object>() { @Override public void subscribe(Subscriber<? super Object> observer) { observer.onSubscribe(new BooleanSubscription()); push(observer, new Object(), 100); push(observer, new Object(), 200); push(observer, new Object(), 300); complete(observer, 301); } }); } }; Flowable<List<String>> buffered = source.buffer(closer); buffered.subscribe(observer); InOrder inOrder = Mockito.inOrder(observer); scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four")); inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); inOrder.verify(observer, Mockito.never()).onNext(Mockito.<String>anyList()); inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); inOrder.verify(observer, Mockito.times(1)).onComplete(); } @Test public void testLongTimeAction() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); LongTimeAction action = new LongTimeAction(latch); Flowable.just(1).buffer(10, TimeUnit.MILLISECONDS, 10) .subscribe(action); latch.await(); assertFalse(action.fail); } static final class LongTimeAction implements Consumer<List<Integer>> { CountDownLatch latch; boolean fail; LongTimeAction(CountDownLatch latch) { this.latch = latch; } @Override public void accept(List<Integer> t1) { try { if (fail) { return; } Thread.sleep(200); } catch (InterruptedException e) { fail = true; } finally { latch.countDown(); } } } private List<String> list(String... args) { List<String> list = new ArrayList<String>(); for (String arg : args) { list.add(arg); } return list; } private <T> void push(final Subscriber<T> observer, final T value, int delay) { innerScheduler.schedule(new Runnable() { @Override public void run() { observer.onNext(value); } }, delay, TimeUnit.MILLISECONDS); } private void complete(final Subscriber<?> observer, int delay) { innerScheduler.schedule(new Runnable() { @Override public void run() { observer.onComplete(); } }, delay, TimeUnit.MILLISECONDS); } @Test public void testBufferStopsWhenUnsubscribed1() { Flowable<Integer> source = Flowable.never(); Subscriber<List<Integer>> o = TestHelper.mockSubscriber(); TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(o, 0L); source.buffer(100, 200, TimeUnit.MILLISECONDS, scheduler) .doOnNext(new Consumer<List<Integer>>() { @Override public void accept(List<Integer> pv) { System.out.println(pv); } }) .subscribe(ts); InOrder inOrder = Mockito.inOrder(o); scheduler.advanceTimeBy(1001, TimeUnit.MILLISECONDS); inOrder.verify(o, times(5)).onNext(Arrays.<Integer> asList()); ts.dispose(); scheduler.advanceTimeBy(999, TimeUnit.MILLISECONDS); inOrder.verifyNoMoreInteractions(); } @Test public void bufferWithBONormal1() { PublishProcessor<Integer> source = PublishProcessor.create(); PublishProcessor<Integer> boundary = PublishProcessor.create(); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = Mockito.inOrder(o); source.buffer(boundary).subscribe(o); source.onNext(1); source.onNext(2); source.onNext(3); boundary.onNext(1); inOrder.verify(o, times(1)).onNext(Arrays.asList(1, 2, 3)); source.onNext(4); source.onNext(5); boundary.onNext(2); inOrder.verify(o, times(1)).onNext(Arrays.asList(4, 5)); source.onNext(6); boundary.onComplete(); inOrder.verify(o, times(1)).onNext(Arrays.asList(6)); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test public void bufferWithBOEmptyLastViaBoundary() { PublishProcessor<Integer> source = PublishProcessor.create(); PublishProcessor<Integer> boundary = PublishProcessor.create(); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = Mockito.inOrder(o); source.buffer(boundary).subscribe(o); boundary.onComplete(); inOrder.verify(o, times(1)).onNext(Arrays.asList()); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test public void bufferWithBOEmptyLastViaSource() { PublishProcessor<Integer> source = PublishProcessor.create(); PublishProcessor<Integer> boundary = PublishProcessor.create(); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = Mockito.inOrder(o); source.buffer(boundary).subscribe(o); source.onComplete(); inOrder.verify(o, times(1)).onNext(Arrays.asList()); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test public void bufferWithBOEmptyLastViaBoth() { PublishProcessor<Integer> source = PublishProcessor.create(); PublishProcessor<Integer> boundary = PublishProcessor.create(); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = Mockito.inOrder(o); source.buffer(boundary).subscribe(o); source.onComplete(); boundary.onComplete(); inOrder.verify(o, times(1)).onNext(Arrays.asList()); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test public void bufferWithBOSourceThrows() { PublishProcessor<Integer> source = PublishProcessor.create(); PublishProcessor<Integer> boundary = PublishProcessor.create(); Subscriber<Object> o = TestHelper.mockSubscriber(); source.buffer(boundary).subscribe(o); source.onNext(1); source.onError(new TestException()); verify(o).onError(any(TestException.class)); verify(o, never()).onComplete(); verify(o, never()).onNext(any()); } @Test public void bufferWithBOBoundaryThrows() { PublishProcessor<Integer> source = PublishProcessor.create(); PublishProcessor<Integer> boundary = PublishProcessor.create(); Subscriber<Object> o = TestHelper.mockSubscriber(); source.buffer(boundary).subscribe(o); source.onNext(1); boundary.onError(new TestException()); verify(o).onError(any(TestException.class)); verify(o, never()).onComplete(); verify(o, never()).onNext(any()); } @Test(timeout = 2000) public void bufferWithSizeTake1() { Flowable<Integer> source = Flowable.just(1).repeat(); Flowable<List<Integer>> result = source.buffer(2).take(1); Subscriber<Object> o = TestHelper.mockSubscriber(); result.subscribe(o); verify(o).onNext(Arrays.asList(1, 1)); verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test(timeout = 2000) public void bufferWithSizeSkipTake1() { Flowable<Integer> source = Flowable.just(1).repeat(); Flowable<List<Integer>> result = source.buffer(2, 3).take(1); Subscriber<Object> o = TestHelper.mockSubscriber(); result.subscribe(o); verify(o).onNext(Arrays.asList(1, 1)); verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test(timeout = 2000) public void bufferWithTimeTake1() { Flowable<Long> source = Flowable.interval(40, 40, TimeUnit.MILLISECONDS, scheduler); Flowable<List<Long>> result = source.buffer(100, TimeUnit.MILLISECONDS, scheduler).take(1); Subscriber<Object> o = TestHelper.mockSubscriber(); result.subscribe(o); scheduler.advanceTimeBy(5, TimeUnit.SECONDS); verify(o).onNext(Arrays.asList(0L, 1L)); verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test(timeout = 2000) public void bufferWithTimeSkipTake2() { Flowable<Long> source = Flowable.interval(40, 40, TimeUnit.MILLISECONDS, scheduler); Flowable<List<Long>> result = source.buffer(100, 60, TimeUnit.MILLISECONDS, scheduler).take(2); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = inOrder(o); result.subscribe(o); scheduler.advanceTimeBy(5, TimeUnit.SECONDS); inOrder.verify(o).onNext(Arrays.asList(0L, 1L)); inOrder.verify(o).onNext(Arrays.asList(1L, 2L)); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test(timeout = 2000) public void bufferWithBoundaryTake2() { Flowable<Long> boundary = Flowable.interval(60, 60, TimeUnit.MILLISECONDS, scheduler); Flowable<Long> source = Flowable.interval(40, 40, TimeUnit.MILLISECONDS, scheduler); Flowable<List<Long>> result = source.buffer(boundary).take(2); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = inOrder(o); result.subscribe(o); scheduler.advanceTimeBy(5, TimeUnit.SECONDS); inOrder.verify(o).onNext(Arrays.asList(0L)); inOrder.verify(o).onNext(Arrays.asList(1L)); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test(timeout = 2000) public void bufferWithStartEndBoundaryTake2() { Flowable<Long> start = Flowable.interval(61, 61, TimeUnit.MILLISECONDS, scheduler); Function<Long, Flowable<Long>> end = new Function<Long, Flowable<Long>>() { @Override public Flowable<Long> apply(Long t1) { return Flowable.interval(100, 100, TimeUnit.MILLISECONDS, scheduler); } }; Flowable<Long> source = Flowable.interval(40, 40, TimeUnit.MILLISECONDS, scheduler); Flowable<List<Long>> result = source.buffer(start, end).take(2); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = inOrder(o); result .doOnNext(new Consumer<List<Long>>() { @Override public void accept(List<Long> pv) { System.out.println(pv); } }) .subscribe(o); scheduler.advanceTimeBy(5, TimeUnit.SECONDS); inOrder.verify(o).onNext(Arrays.asList(1L, 2L, 3L)); inOrder.verify(o).onNext(Arrays.asList(3L, 4L)); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test public void bufferWithSizeThrows() { PublishProcessor<Integer> source = PublishProcessor.create(); Flowable<List<Integer>> result = source.buffer(2); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = inOrder(o); result.subscribe(o); source.onNext(1); source.onNext(2); source.onNext(3); source.onError(new TestException()); inOrder.verify(o).onNext(Arrays.asList(1, 2)); inOrder.verify(o).onError(any(TestException.class)); inOrder.verifyNoMoreInteractions(); verify(o, never()).onNext(Arrays.asList(3)); verify(o, never()).onComplete(); } @Test public void bufferWithTimeThrows() { PublishProcessor<Integer> source = PublishProcessor.create(); Flowable<List<Integer>> result = source.buffer(100, TimeUnit.MILLISECONDS, scheduler); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = inOrder(o); result.subscribe(o); source.onNext(1); source.onNext(2); scheduler.advanceTimeBy(100, TimeUnit.MILLISECONDS); source.onNext(3); source.onError(new TestException()); scheduler.advanceTimeBy(100, TimeUnit.MILLISECONDS); inOrder.verify(o).onNext(Arrays.asList(1, 2)); inOrder.verify(o).onError(any(TestException.class)); inOrder.verifyNoMoreInteractions(); verify(o, never()).onNext(Arrays.asList(3)); verify(o, never()).onComplete(); } @Test public void bufferWithTimeAndSize() { Flowable<Long> source = Flowable.interval(30, 30, TimeUnit.MILLISECONDS, scheduler); Flowable<List<Long>> result = source.buffer(100, TimeUnit.MILLISECONDS, scheduler, 2).take(3); Subscriber<Object> o = TestHelper.mockSubscriber(); InOrder inOrder = inOrder(o); result.subscribe(o); scheduler.advanceTimeBy(5, TimeUnit.SECONDS); inOrder.verify(o).onNext(Arrays.asList(0L, 1L)); inOrder.verify(o).onNext(Arrays.asList(2L)); inOrder.verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); } @Test public void bufferWithStartEndStartThrows() { PublishProcessor<Integer> start = PublishProcessor.create(); Function<Integer, Flowable<Integer>> end = new Function<Integer, Flowable<Integer>>() { @Override public Flowable<Integer> apply(Integer t1) { return Flowable.never(); } }; PublishProcessor<Integer> source = PublishProcessor.create(); Flowable<List<Integer>> result = source.buffer(start, end); Subscriber<Object> o = TestHelper.mockSubscriber(); result.subscribe(o); start.onNext(1); source.onNext(1); source.onNext(2); start.onError(new TestException()); verify(o, never()).onNext(any()); verify(o, never()).onComplete(); verify(o).onError(any(TestException.class)); } @Test public void bufferWithStartEndEndFunctionThrows() { PublishProcessor<Integer> start = PublishProcessor.create(); Function<Integer, Flowable<Integer>> end = new Function<Integer, Flowable<Integer>>() { @Override public Flowable<Integer> apply(Integer t1) { throw new TestException(); } }; PublishProcessor<Integer> source = PublishProcessor.create(); Flowable<List<Integer>> result = source.buffer(start, end); Subscriber<Object> o = TestHelper.mockSubscriber(); result.subscribe(o); start.onNext(1); source.onNext(1); source.onNext(2); verify(o, never()).onNext(any()); verify(o, never()).onComplete(); verify(o).onError(any(TestException.class)); } @Test public void bufferWithStartEndEndThrows() { PublishProcessor<Integer> start = PublishProcessor.create(); Function<Integer, Flowable<Integer>> end = new Function<Integer, Flowable<Integer>>() { @Override public Flowable<Integer> apply(Integer t1) { return Flowable.error(new TestException()); } }; PublishProcessor<Integer> source = PublishProcessor.create(); Flowable<List<Integer>> result = source.buffer(start, end); Subscriber<Object> o = TestHelper.mockSubscriber(); result.subscribe(o); start.onNext(1); source.onNext(1); source.onNext(2); verify(o, never()).onNext(any()); verify(o, never()).onComplete(); verify(o).onError(any(TestException.class)); } @Test public void testProducerRequestThroughBufferWithSize1() { TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(3L); final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } }); } }).buffer(5, 5).subscribe(ts); assertEquals(15, requested.get()); ts.request(4); assertEquals(20, requested.get()); } @Test public void testProducerRequestThroughBufferWithSize2() { TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(); final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } }); } }).buffer(5, 5).subscribe(ts); assertEquals(Long.MAX_VALUE, requested.get()); } @Test public void testProducerRequestThroughBufferWithSize3() { TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(3L); final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } }); } }).buffer(5, 2).subscribe(ts); assertEquals(9, requested.get()); ts.request(3); assertEquals(6, requested.get()); } @Test public void testProducerRequestThroughBufferWithSize4() { TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(); final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } }); } }).buffer(5, 2).subscribe(ts); assertEquals(Long.MAX_VALUE, requested.get()); } @Test public void testProducerRequestOverflowThroughBufferWithSize1() { TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(Long.MAX_VALUE >> 1); final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } }); } }).buffer(3, 3).subscribe(ts); assertEquals(Long.MAX_VALUE, requested.get()); } @Test public void testProducerRequestOverflowThroughBufferWithSize2() { TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>(Long.MAX_VALUE >> 1); final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } }); } }).buffer(3, 2).subscribe(ts); assertEquals(Long.MAX_VALUE, requested.get()); } @Test public void testProducerRequestOverflowThroughBufferWithSize3() { final AtomicLong requested = new AtomicLong(); Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(final Subscriber<? super Integer> s) { s.onSubscribe(new Subscription() { AtomicBoolean once = new AtomicBoolean(); @Override public void request(long n) { requested.set(n); if (once.compareAndSet(false, true)) { s.onNext(1); s.onNext(2); s.onNext(3); } } @Override public void cancel() { } }); } }).buffer(3, 2).subscribe(new DefaultSubscriber<List<Integer>>() { @Override public void onStart() { request(Long.MAX_VALUE / 2 - 4); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(List<Integer> t) { request(Long.MAX_VALUE / 2); } }); // FIXME I'm not sure why this is MAX_VALUE in 1.x because MAX_VALUE/2 is even and thus can't overflow when multiplied by 2 assertEquals(Long.MAX_VALUE - 1, requested.get()); } @Test(timeout = 3000) public void testBufferWithTimeDoesntUnsubscribeDownstream() throws InterruptedException { final Subscriber<Object> o = TestHelper.mockSubscriber(); final CountDownLatch cdl = new CountDownLatch(1); ResourceSubscriber<Object> s = new ResourceSubscriber<Object>() { @Override public void onNext(Object t) { o.onNext(t); } @Override public void onError(Throwable e) { o.onError(e); cdl.countDown(); } @Override public void onComplete() { o.onComplete(); cdl.countDown(); } }; Flowable.range(1, 1).delay(1, TimeUnit.SECONDS).buffer(2, TimeUnit.SECONDS).subscribe(s); cdl.await(); verify(o).onNext(Arrays.asList(1)); verify(o).onComplete(); verify(o, never()).onError(any(Throwable.class)); assertFalse(s.isDisposed()); } @SuppressWarnings("unchecked") @Test public void testPostCompleteBackpressure() { Flowable<List<Integer>> source = Flowable.range(1, 10).buffer(3, 1); TestSubscriber<List<Integer>> ts = TestSubscriber.create(0L); source.subscribe(ts); ts.assertNoValues(); ts.assertNotComplete(); ts.assertNoErrors(); ts.request(7); ts.assertValues( Arrays.asList(1, 2, 3), Arrays.asList(2, 3, 4), Arrays.asList(3, 4, 5), Arrays.asList(4, 5, 6), Arrays.asList(5, 6, 7), Arrays.asList(6, 7, 8), Arrays.asList(7, 8, 9) ); ts.assertNotComplete(); ts.assertNoErrors(); ts.request(1); ts.assertValues( Arrays.asList(1, 2, 3), Arrays.asList(2, 3, 4), Arrays.asList(3, 4, 5), Arrays.asList(4, 5, 6), Arrays.asList(5, 6, 7), Arrays.asList(6, 7, 8), Arrays.asList(7, 8, 9), Arrays.asList(8, 9, 10) ); ts.assertNotComplete(); ts.assertNoErrors(); ts.request(1); ts.assertValues( Arrays.asList(1, 2, 3), Arrays.asList(2, 3, 4), Arrays.asList(3, 4, 5), Arrays.asList(4, 5, 6), Arrays.asList(5, 6, 7), Arrays.asList(6, 7, 8), Arrays.asList(7, 8, 9), Arrays.asList(8, 9, 10), Arrays.asList(9, 10) ); ts.assertNotComplete(); ts.assertNoErrors(); ts.request(1); ts.assertValues( Arrays.asList(1, 2, 3), Arrays.asList(2, 3, 4), Arrays.asList(3, 4, 5), Arrays.asList(4, 5, 6), Arrays.asList(5, 6, 7), Arrays.asList(6, 7, 8), Arrays.asList(7, 8, 9), Arrays.asList(8, 9, 10), Arrays.asList(9, 10), Arrays.asList(10) ); ts.assertComplete(); ts.assertNoErrors(); } @SuppressWarnings("unchecked") @Test public void timeAndSkipOverlap() { PublishProcessor<Integer> ps = PublishProcessor.create(); TestSubscriber<List<Integer>> ts = TestSubscriber.create(); ps.buffer(2, 1, TimeUnit.SECONDS, scheduler).subscribe(ts); ps.onNext(1); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(2); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(3); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(4); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onComplete(); ts.assertValues( Arrays.asList(1, 2), Arrays.asList(2, 3), Arrays.asList(3, 4), Arrays.asList(4), Collections.<Integer>emptyList() ); ts.assertNoErrors(); ts.assertComplete(); } @SuppressWarnings("unchecked") @Test public void timeAndSkipSkip() { PublishProcessor<Integer> ps = PublishProcessor.create(); TestSubscriber<List<Integer>> ts = TestSubscriber.create(); ps.buffer(2, 3, TimeUnit.SECONDS, scheduler).subscribe(ts); ps.onNext(1); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(2); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(3); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(4); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onComplete(); ts.assertValues( Arrays.asList(1, 2), Arrays.asList(4) ); ts.assertNoErrors(); ts.assertComplete(); } @SuppressWarnings("unchecked") @Test public void timeAndSkipOverlapScheduler() { RxJavaPlugins.setComputationSchedulerHandler(new Function<Scheduler, Scheduler>() { @Override public Scheduler apply(Scheduler t) { return scheduler; } }); try { PublishProcessor<Integer> ps = PublishProcessor.create(); TestSubscriber<List<Integer>> ts = TestSubscriber.create(); ps.buffer(2, 1, TimeUnit.SECONDS).subscribe(ts); ps.onNext(1); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(2); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(3); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(4); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onComplete(); ts.assertValues( Arrays.asList(1, 2), Arrays.asList(2, 3), Arrays.asList(3, 4), Arrays.asList(4), Collections.<Integer>emptyList() ); ts.assertNoErrors(); ts.assertComplete(); } finally { RxJavaPlugins.reset(); } } @SuppressWarnings("unchecked") @Test public void timeAndSkipSkipDefaultScheduler() { RxJavaPlugins.setComputationSchedulerHandler(new Function<Scheduler, Scheduler>() { @Override public Scheduler apply(Scheduler t) { return scheduler; } }); try { PublishProcessor<Integer> ps = PublishProcessor.create(); TestSubscriber<List<Integer>> ts = TestSubscriber.create(); ps.buffer(2, 3, TimeUnit.SECONDS).subscribe(ts); ps.onNext(1); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(2); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(3); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onNext(4); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); ps.onComplete(); ts.assertValues( Arrays.asList(1, 2), Arrays.asList(4) ); ts.assertNoErrors(); ts.assertComplete(); } finally { RxJavaPlugins.reset(); } } @SuppressWarnings("unchecked") @Test public void bufferBoundaryHint() { Flowable.range(1, 5).buffer(Flowable.timer(1, TimeUnit.MINUTES), 2) .test() .assertResult(Arrays.asList(1, 2, 3, 4, 5)); } static HashSet<Integer> set(Integer... values) { return new HashSet<Integer>(Arrays.asList(values)); } @SuppressWarnings("unchecked") @Test public void bufferIntoCustomCollection() { Flowable.just(1, 1, 2, 2, 3, 3, 4, 4) .buffer(3, new Callable<Collection<Integer>>() { @Override public Collection<Integer> call() throws Exception { return new HashSet<Integer>(); } }) .test() .assertResult(set(1, 2), set(2, 3), set(4)); } @SuppressWarnings("unchecked") @Test public void bufferSkipIntoCustomCollection() { Flowable.just(1, 1, 2, 2, 3, 3, 4, 4) .buffer(3, 3, new Callable<Collection<Integer>>() { @Override public Collection<Integer> call() throws Exception { return new HashSet<Integer>(); } }) .test() .assertResult(set(1, 2), set(2, 3), set(4)); } @SuppressWarnings("unchecked") @Test public void bufferTimeSkipDefault() { Flowable.range(1, 5).buffer(1, 1, TimeUnit.MINUTES) .test() .assertResult(Arrays.asList(1, 2, 3, 4, 5)); } @Test @SuppressWarnings("unchecked") public void boundaryBufferSupplierThrows() { Flowable.never() .buffer(Functions.justCallable(Flowable.never()), new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { throw new TestException(); } }) .test() .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void boundaryBoundarySupplierThrows() { Flowable.never() .buffer(new Callable<Publisher<Object>>() { @Override public Publisher<Object> call() throws Exception { throw new TestException(); } }, new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test() .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void boundaryBufferSupplierThrows2() { Flowable.never() .buffer(Functions.justCallable(Flowable.timer(1, TimeUnit.MILLISECONDS)), new Callable<Collection<Object>>() { int count; @Override public Collection<Object> call() throws Exception { if (count++ == 1) { throw new TestException(); } else { return new ArrayList<Object>(); } } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void boundaryBufferSupplierReturnsNull() { Flowable.never() .buffer(Functions.justCallable(Flowable.timer(1, TimeUnit.MILLISECONDS)), new Callable<Collection<Object>>() { int count; @Override public Collection<Object> call() throws Exception { if (count++ == 1) { return null; } else { return new ArrayList<Object>(); } } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(NullPointerException.class); } @Test @SuppressWarnings("unchecked") public void boundaryBoundarySupplierThrows2() { Flowable.never() .buffer(new Callable<Publisher<Long>>() { int count; @Override public Publisher<Long> call() throws Exception { if (count++ == 1) { throw new TestException(); } return Flowable.timer(1, TimeUnit.MILLISECONDS); } }, new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class); } @Test public void boundaryCancel() { PublishProcessor<Object> pp = PublishProcessor.create(); TestSubscriber<Collection<Object>> ts = pp .buffer(Functions.justCallable(Flowable.never()), new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test(); assertTrue(pp.hasSubscribers()); ts.dispose(); assertFalse(pp.hasSubscribers()); } @Test @SuppressWarnings("unchecked") public void boundaryBoundarySupplierReturnsNull() { Flowable.never() .buffer(new Callable<Publisher<Long>>() { int count; @Override public Publisher<Long> call() throws Exception { if (count++ == 1) { return null; } return Flowable.timer(1, TimeUnit.MILLISECONDS); } }, new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(NullPointerException.class); } @Test @SuppressWarnings("unchecked") public void boundaryBoundarySupplierReturnsNull2() { Flowable.never() .buffer(new Callable<Publisher<Long>>() { int count; @Override public Publisher<Long> call() throws Exception { if (count++ == 1) { return null; } return Flowable.empty(); } }, new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(NullPointerException.class); } @SuppressWarnings("unchecked") @Test public void boundaryMainError() { PublishProcessor<Object> pp = PublishProcessor.create(); TestSubscriber<Collection<Object>> ts = pp .buffer(Functions.justCallable(Flowable.never()), new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test(); pp.onError(new TestException()); ts.assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void boundaryBoundaryError() { PublishProcessor<Object> pp = PublishProcessor.create(); TestSubscriber<Collection<Object>> ts = pp .buffer(Functions.justCallable(Flowable.error(new TestException())), new Callable<Collection<Object>>() { @Override public Collection<Object> call() throws Exception { return new ArrayList<Object>(); } }) .test(); pp.onError(new TestException()); ts.assertFailure(TestException.class); } @Test public void dispose() { TestHelper.checkDisposed(Flowable.range(1, 5).buffer(1, TimeUnit.DAYS, Schedulers.single())); TestHelper.checkDisposed(Flowable.range(1, 5).buffer(2, 1, TimeUnit.DAYS, Schedulers.single())); TestHelper.checkDisposed(Flowable.range(1, 5).buffer(1, 2, TimeUnit.DAYS, Schedulers.single())); TestHelper.checkDisposed(Flowable.range(1, 5) .buffer(1, TimeUnit.DAYS, Schedulers.single(), 2, Functions.<Integer>createArrayList(16), true)); TestHelper.checkDisposed(Flowable.range(1, 5).buffer(1)); TestHelper.checkDisposed(Flowable.range(1, 5).buffer(2, 1)); TestHelper.checkDisposed(Flowable.range(1, 5).buffer(1, 2)); } @Test @SuppressWarnings("unchecked") public void supplierReturnsNull() { Flowable.<Integer>never() .buffer(1, TimeUnit.MILLISECONDS, Schedulers.single(), Integer.MAX_VALUE, new Callable<Collection<Integer>>() { int count; @Override public Collection<Integer> call() throws Exception { if (count++ == 1) { return null; } else { return new ArrayList<Integer>(); } } }, false) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(NullPointerException.class); } @Test @SuppressWarnings("unchecked") public void supplierReturnsNull2() { Flowable.<Integer>never() .buffer(1, TimeUnit.MILLISECONDS, Schedulers.single(), 10, new Callable<Collection<Integer>>() { int count; @Override public Collection<Integer> call() throws Exception { if (count++ == 1) { return null; } else { return new ArrayList<Integer>(); } } }, false) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(NullPointerException.class); } @Test @SuppressWarnings("unchecked") public void supplierReturnsNull3() { Flowable.<Integer>never() .buffer(2, 1, TimeUnit.MILLISECONDS, Schedulers.single(), new Callable<Collection<Integer>>() { int count; @Override public Collection<Integer> call() throws Exception { if (count++ == 1) { return null; } else { return new ArrayList<Integer>(); } } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(NullPointerException.class); } @Test @SuppressWarnings("unchecked") public void supplierThrows() { Flowable.just(1) .buffer(1, TimeUnit.SECONDS, Schedulers.single(), Integer.MAX_VALUE, new Callable<Collection<Integer>>() { @Override public Collection<Integer> call() throws Exception { throw new TestException(); } }, false) .test() .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void supplierThrows2() { Flowable.just(1) .buffer(1, TimeUnit.SECONDS, Schedulers.single(), 10, new Callable<Collection<Integer>>() { @Override public Collection<Integer> call() throws Exception { throw new TestException(); } }, false) .test() .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void supplierThrows3() { Flowable.just(1) .buffer(2, 1, TimeUnit.SECONDS, Schedulers.single(), new Callable<Collection<Integer>>() { @Override public Collection<Integer> call() throws Exception { throw new TestException(); } }) .test() .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void supplierThrows4() { Flowable.<Integer>never() .buffer(1, TimeUnit.MILLISECONDS, Schedulers.single(), Integer.MAX_VALUE, new Callable<Collection<Integer>>() { int count; @Override public Collection<Integer> call() throws Exception { if (count++ == 1) { throw new TestException(); } else { return new ArrayList<Integer>(); } } }, false) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void supplierThrows5() { Flowable.<Integer>never() .buffer(1, TimeUnit.MILLISECONDS, Schedulers.single(), 10, new Callable<Collection<Integer>>() { int count; @Override public Collection<Integer> call() throws Exception { if (count++ == 1) { throw new TestException(); } else { return new ArrayList<Integer>(); } } }, false) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class); } @Test @SuppressWarnings("unchecked") public void supplierThrows6() { Flowable.<Integer>never() .buffer(2, 1, TimeUnit.MILLISECONDS, Schedulers.single(), new Callable<Collection<Integer>>() { int count; @Override public Collection<Integer> call() throws Exception { if (count++ == 1) { throw new TestException(); } else { return new ArrayList<Integer>(); } } }) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void restartTimer() { Flowable.range(1, 5) .buffer(1, TimeUnit.DAYS, Schedulers.single(), 2, Functions.<Integer>createArrayList(16), true) .test() .assertResult(Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5)); } @SuppressWarnings("unchecked") @Test public void bufferSkipError() { Flowable.<Integer>error(new TestException()) .buffer(2, 1) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void bufferSupplierCrash2() { Flowable.range(1, 2) .buffer(1, new Callable<List<Integer>>() { int calls; @Override public List<Integer> call() throws Exception { if (++calls == 2) { throw new TestException(); } return new ArrayList<Integer>(); } }) .test() .assertFailure(TestException.class, Arrays.asList(1)); } @SuppressWarnings("unchecked") @Test public void bufferSkipSupplierCrash2() { Flowable.range(1, 2) .buffer(1, 2, new Callable<List<Integer>>() { int calls; @Override public List<Integer> call() throws Exception { if (++calls == 1) { throw new TestException(); } return new ArrayList<Integer>(); } }) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void bufferOverlapSupplierCrash2() { Flowable.range(1, 2) .buffer(2, 1, new Callable<List<Integer>>() { int calls; @Override public List<Integer> call() throws Exception { if (++calls == 2) { throw new TestException(); } return new ArrayList<Integer>(); } }) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void bufferSkipOverlap() { Flowable.range(1, 5) .buffer(5, 1) .test() .assertResult( Arrays.asList(1, 2, 3, 4, 5), Arrays.asList(2, 3, 4, 5), Arrays.asList(3, 4, 5), Arrays.asList(4, 5), Arrays.asList(5) ); } @SuppressWarnings("unchecked") @Test public void bufferTimedExactError() { Flowable.error(new TestException()) .buffer(1, TimeUnit.DAYS) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void bufferTimedSkipError() { Flowable.error(new TestException()) .buffer(1, 2, TimeUnit.DAYS) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void bufferTimedOverlapError() { Flowable.error(new TestException()) .buffer(2, 1, TimeUnit.DAYS) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void bufferTimedExactEmpty() { Flowable.empty() .buffer(1, TimeUnit.DAYS) .test() .assertResult(Collections.emptyList()); } @SuppressWarnings("unchecked") @Test public void bufferTimedSkipEmpty() { Flowable.empty() .buffer(1, 2, TimeUnit.DAYS) .test() .assertResult(Collections.emptyList()); } @SuppressWarnings("unchecked") @Test public void bufferTimedOverlapEmpty() { Flowable.empty() .buffer(2, 1, TimeUnit.DAYS) .test() .assertResult(Collections.emptyList()); } @SuppressWarnings("unchecked") @Test public void bufferTimedExactSupplierCrash() { TestScheduler scheduler = new TestScheduler(); PublishProcessor<Integer> ps = PublishProcessor.create(); TestSubscriber<List<Integer>> to = ps .buffer(1, TimeUnit.MILLISECONDS, scheduler, 1, new Callable<List<Integer>>() { int calls; @Override public List<Integer> call() throws Exception { if (++calls == 2) { throw new TestException(); } return new ArrayList<Integer>(); } }, true) .test(); ps.onNext(1); scheduler.advanceTimeBy(1, TimeUnit.MILLISECONDS); ps.onNext(2); to .assertFailure(TestException.class, Arrays.asList(1)); } @SuppressWarnings("unchecked") @Test public void bufferTimedExactBoundedError() { TestScheduler scheduler = new TestScheduler(); PublishProcessor<Integer> ps = PublishProcessor.create(); TestSubscriber<List<Integer>> to = ps .buffer(1, TimeUnit.MILLISECONDS, scheduler, 1, Functions.<Integer>createArrayList(16), true) .test(); ps.onError(new TestException()); to .assertFailure(TestException.class); } @Test public void badSource() { TestHelper.checkBadSourceFlowable(new Function<Flowable<Integer>, Object>() { @Override public Object apply(Flowable<Integer> f) throws Exception { return f.buffer(1); } }, false, 1, 1, Arrays.asList(1)); TestHelper.checkBadSourceFlowable(new Function<Flowable<Integer>, Object>() { @Override public Object apply(Flowable<Integer> f) throws Exception { return f.buffer(1, 2); } }, false, 1, 1, Arrays.asList(1)); TestHelper.checkBadSourceFlowable(new Function<Flowable<Integer>, Object>() { @Override public Object apply(Flowable<Integer> f) throws Exception { return f.buffer(2, 1); } }, false, 1, 1, Arrays.asList(1)); } @Test public void doubleOnSubscribe() { TestHelper.checkDoubleOnSubscribeFlowable(new Function<Flowable<Object>, Publisher<List<Object>>>() { @Override public Publisher<List<Object>> apply(Flowable<Object> f) throws Exception { return f.buffer(1); } }); TestHelper.checkDoubleOnSubscribeFlowable(new Function<Flowable<Object>, Publisher<List<Object>>>() { @Override public Publisher<List<Object>> apply(Flowable<Object> f) throws Exception { return f.buffer(1, 2); } }); TestHelper.checkDoubleOnSubscribeFlowable(new Function<Flowable<Object>, Publisher<List<Object>>>() { @Override public Publisher<List<Object>> apply(Flowable<Object> f) throws Exception { return f.buffer(2, 1); } }); } @Test public void badRequest() { TestHelper.assertBadRequestReported(PublishProcessor.create().buffer(1)); TestHelper.assertBadRequestReported(PublishProcessor.create().buffer(1, 2)); TestHelper.assertBadRequestReported(PublishProcessor.create().buffer(2, 1)); } @SuppressWarnings("unchecked") @Test public void skipError() { Flowable.error(new TestException()) .buffer(1, 2) .test() .assertFailure(TestException.class); } @SuppressWarnings("unchecked") @Test public void skipSingleResult() { Flowable.just(1) .buffer(2, 3) .test() .assertResult(Arrays.asList(1)); } @SuppressWarnings("unchecked") @Test public void skipBackpressure() { Flowable.range(1, 10) .buffer(2, 3) .rebatchRequests(1) .test() .assertResult(Arrays.asList(1, 2), Arrays.asList(4, 5), Arrays.asList(7, 8), Arrays.asList(10)); } }