/**
* Copyright 2014 Netflix, Inc.
*
* 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 rx.internal.operators;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import rx.Observable;
import rx.Observer;
import rx.Producer;
import rx.Scheduler;
import rx.Subscriber;
import rx.Subscription;
import rx.exceptions.TestException;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.observers.TestSubscriber;
import rx.schedulers.TestScheduler;
import rx.subjects.PublishSubject;
public class OperatorBufferTest {
private Observer<List<String>> observer;
private TestScheduler scheduler;
private Scheduler.Worker innerScheduler;
@Before
@SuppressWarnings("unchecked")
public void before() {
observer = Mockito.mock(Observer.class);
scheduler = new TestScheduler();
innerScheduler = scheduler.createWorker();
}
@Test
public void testComplete() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
observer.onCompleted();
}
});
Observable<List<String>> buffered = source.buffer(3, 3);
buffered.subscribe(observer);
Mockito.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class));
Mockito.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
Mockito.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testSkipAndCountOverlappingBuffers() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
observer.onNext("one");
observer.onNext("two");
observer.onNext("three");
observer.onNext("four");
observer.onNext("five");
}
});
Observable<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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.never()).onCompleted();
}
@Test
public void testSkipAndCountGaplessBuffers() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
observer.onNext("one");
observer.onNext("two");
observer.onNext("three");
observer.onNext("four");
observer.onNext("five");
observer.onCompleted();
}
});
Observable<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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testSkipAndCountBuffersWithGaps() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
observer.onNext("one");
observer.onNext("two");
observer.onNext("three");
observer.onNext("four");
observer.onNext("five");
observer.onCompleted();
}
});
Observable<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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testTimedAndCount() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
push(observer, "one", 10);
push(observer, "two", 90);
push(observer, "three", 110);
push(observer, "four", 190);
push(observer, "five", 210);
complete(observer, 250);
}
});
Observable<List<String>> buffered = source.buffer(100, TimeUnit.MILLISECONDS, 2, scheduler);
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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testTimed() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
push(observer, "one", 97);
push(observer, "two", 98);
/**
* Changed from 100. Because scheduling the cut to 100ms happens before this
* Observable 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);
}
});
Observable<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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testObservableBasedOpenerAndCloser() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
push(observer, "one", 10);
push(observer, "two", 60);
push(observer, "three", 110);
push(observer, "four", 160);
push(observer, "five", 210);
complete(observer, 500);
}
});
Observable<Object> openings = Observable.create(new Observable.OnSubscribe<Object>() {
@Override
public void call(Subscriber<Object> observer) {
push(observer, new Object(), 50);
push(observer, new Object(), 200);
complete(observer, 250);
}
});
Func1<Object, Observable<Object>> closer = new Func1<Object, Observable<Object>>() {
@Override
public Observable<Object> call(Object opening) {
return Observable.create(new Observable.OnSubscribe<Object>() {
@Override
public void call(Subscriber<? super Object> observer) {
push(observer, new Object(), 100);
complete(observer, 101);
}
});
}
};
Observable<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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testObservableBasedCloser() {
Observable<String> source = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
push(observer, "one", 10);
push(observer, "two", 60);
push(observer, "three", 110);
push(observer, "four", 160);
push(observer, "five", 210);
complete(observer, 250);
}
});
Func0<Observable<Object>> closer = new Func0<Observable<Object>>() {
@Override
public Observable<Object> call() {
return Observable.create(new Observable.OnSubscribe<Object>() {
@Override
public void call(Subscriber<? super Object> observer) {
push(observer, new Object(), 100);
push(observer, new Object(), 200);
push(observer, new Object(), 300);
complete(observer, 301);
}
});
}
};
Observable<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.anyListOf(String.class));
inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class));
inOrder.verify(observer, Mockito.times(1)).onCompleted();
}
@Test
public void testLongTimeAction() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
LongTimeAction action = new LongTimeAction(latch);
Observable.just(1).buffer(10, TimeUnit.MILLISECONDS, 10)
.subscribe(action);
latch.await();
assertFalse(action.fail);
}
private static class LongTimeAction implements Action1<List<Integer>> {
CountDownLatch latch;
boolean fail = false;
public LongTimeAction(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void call(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 Observer<T> observer, final T value, int delay) {
innerScheduler.schedule(new Action0() {
@Override
public void call() {
observer.onNext(value);
}
}, delay, TimeUnit.MILLISECONDS);
}
private void complete(final Observer<?> observer, int delay) {
innerScheduler.schedule(new Action0() {
@Override
public void call() {
observer.onCompleted();
}
}, delay, TimeUnit.MILLISECONDS);
}
@Test
public void testBufferStopsWhenUnsubscribed1() {
Observable<Integer> source = Observable.never();
@SuppressWarnings("unchecked")
Observer<List<Integer>> o = mock(Observer.class);
Subscription s = source.buffer(100, 200, TimeUnit.MILLISECONDS, scheduler).subscribe(o);
InOrder inOrder = Mockito.inOrder(o);
scheduler.advanceTimeBy(1001, TimeUnit.MILLISECONDS);
inOrder.verify(o, times(5)).onNext(Arrays.<Integer> asList());
s.unsubscribe();
scheduler.advanceTimeBy(999, TimeUnit.MILLISECONDS);
inOrder.verifyNoMoreInteractions();
}
@Test
public void bufferWithBONormal1() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> boundary = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
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.onCompleted();
inOrder.verify(o, times(1)).onNext(Arrays.asList(6));
inOrder.verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void bufferWithBOEmptyLastViaBoundary() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> boundary = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
InOrder inOrder = Mockito.inOrder(o);
source.buffer(boundary).subscribe(o);
boundary.onCompleted();
inOrder.verify(o, times(1)).onNext(Arrays.asList());
inOrder.verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void bufferWithBOEmptyLastViaSource() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> boundary = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
InOrder inOrder = Mockito.inOrder(o);
source.buffer(boundary).subscribe(o);
source.onCompleted();
inOrder.verify(o, times(1)).onNext(Arrays.asList());
inOrder.verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void bufferWithBOEmptyLastViaBoth() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> boundary = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
InOrder inOrder = Mockito.inOrder(o);
source.buffer(boundary).subscribe(o);
source.onCompleted();
boundary.onCompleted();
inOrder.verify(o, times(1)).onNext(Arrays.asList());
inOrder.verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void bufferWithBOSourceThrows() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> boundary = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
source.buffer(boundary).subscribe(o);
source.onNext(1);
source.onError(new TestException());
verify(o).onError(any(TestException.class));
verify(o, never()).onCompleted();
verify(o, never()).onNext(any());
}
@Test
public void bufferWithBOBoundaryThrows() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> boundary = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
source.buffer(boundary).subscribe(o);
source.onNext(1);
boundary.onError(new TestException());
verify(o).onError(any(TestException.class));
verify(o, never()).onCompleted();
verify(o, never()).onNext(any());
}
@Test(timeout = 2000)
public void bufferWithSizeTake1() {
Observable<Integer> source = Observable.just(1).repeat();
Observable<List<Integer>> result = source.buffer(2).take(1);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
result.subscribe(o);
verify(o).onNext(Arrays.asList(1, 1));
verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test(timeout = 2000)
public void bufferWithSizeSkipTake1() {
Observable<Integer> source = Observable.just(1).repeat();
Observable<List<Integer>> result = source.buffer(2, 3).take(1);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
result.subscribe(o);
verify(o).onNext(Arrays.asList(1, 1));
verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test(timeout = 2000)
public void bufferWithTimeTake1() {
Observable<Long> source = Observable.timer(40, 40, TimeUnit.MILLISECONDS, scheduler);
Observable<List<Long>> result = source.buffer(100, TimeUnit.MILLISECONDS, scheduler).take(1);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
result.subscribe(o);
scheduler.advanceTimeBy(5, TimeUnit.SECONDS);
verify(o).onNext(Arrays.asList(0L, 1L));
verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test(timeout = 2000)
public void bufferWithTimeSkipTake2() {
Observable<Long> source = Observable.timer(40, 40, TimeUnit.MILLISECONDS, scheduler);
Observable<List<Long>> result = source.buffer(100, 60, TimeUnit.MILLISECONDS, scheduler).take(2);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
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).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test(timeout = 2000)
public void bufferWithBoundaryTake2() {
Observable<Long> boundary = Observable.timer(60, 60, TimeUnit.MILLISECONDS, scheduler);
Observable<Long> source = Observable.timer(40, 40, TimeUnit.MILLISECONDS, scheduler);
Observable<List<Long>> result = source.buffer(boundary).take(2);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
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).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test(timeout = 2000)
public void bufferWithStartEndBoundaryTake2() {
Observable<Long> start = Observable.timer(61, 61, TimeUnit.MILLISECONDS, scheduler);
Func1<Long, Observable<Long>> end = new Func1<Long, Observable<Long>>() {
@Override
public Observable<Long> call(Long t1) {
return Observable.timer(100, 100, TimeUnit.MILLISECONDS, scheduler);
}
};
Observable<Long> source = Observable.timer(40, 40, TimeUnit.MILLISECONDS, scheduler);
Observable<List<Long>> result = source.buffer(start, end).take(2);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
InOrder inOrder = inOrder(o);
result.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).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void bufferWithSizeThrows() {
PublishSubject<Integer> source = PublishSubject.create();
Observable<List<Integer>> result = source.buffer(2);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
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()).onCompleted();
}
@Test
public void bufferWithTimeThrows() {
PublishSubject<Integer> source = PublishSubject.create();
Observable<List<Integer>> result = source.buffer(100, TimeUnit.MILLISECONDS, scheduler);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
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()).onCompleted();
}
@Test
public void bufferWithTimeAndSize() {
Observable<Long> source = Observable.timer(30, 30, TimeUnit.MILLISECONDS, scheduler);
Observable<List<Long>> result = source.buffer(100, TimeUnit.MILLISECONDS, 2, scheduler).take(3);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
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).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void bufferWithStartEndStartThrows() {
PublishSubject<Integer> start = PublishSubject.create();
Func1<Integer, Observable<Integer>> end = new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer t1) {
return Observable.never();
}
};
PublishSubject<Integer> source = PublishSubject.create();
Observable<List<Integer>> result = source.buffer(start, end);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
result.subscribe(o);
start.onNext(1);
source.onNext(1);
source.onNext(2);
start.onError(new TestException());
verify(o, never()).onNext(any());
verify(o, never()).onCompleted();
verify(o).onError(any(TestException.class));
}
@Test
public void bufferWithStartEndEndFunctionThrows() {
PublishSubject<Integer> start = PublishSubject.create();
Func1<Integer, Observable<Integer>> end = new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer t1) {
throw new TestException();
}
};
PublishSubject<Integer> source = PublishSubject.create();
Observable<List<Integer>> result = source.buffer(start, end);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
result.subscribe(o);
start.onNext(1);
source.onNext(1);
source.onNext(2);
verify(o, never()).onNext(any());
verify(o, never()).onCompleted();
verify(o).onError(any(TestException.class));
}
@Test
public void bufferWithStartEndEndThrows() {
PublishSubject<Integer> start = PublishSubject.create();
Func1<Integer, Observable<Integer>> end = new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer t1) {
return Observable.error(new TestException());
}
};
PublishSubject<Integer> source = PublishSubject.create();
Observable<List<Integer>> result = source.buffer(start, end);
@SuppressWarnings("unchecked")
Observer<Object> o = mock(Observer.class);
result.subscribe(o);
start.onNext(1);
source.onNext(1);
source.onNext(2);
verify(o, never()).onNext(any());
verify(o, never()).onCompleted();
verify(o).onError(any(TestException.class));
}
@Test
public void testProducerRequestThroughBufferWithSize1() {
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
ts.requestMore(3);
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
}
});
}
}).buffer(5, 5).subscribe(ts);
assertEquals(15, requested.get());
ts.requestMore(4);
assertEquals(20, requested.get());
}
@Test
public void testProducerRequestThroughBufferWithSize2() {
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
}
});
}
}).buffer(5, 5).subscribe(ts);
assertEquals(Long.MAX_VALUE, requested.get());
}
@Test
public void testProducerRequestThroughBufferWithSize3() {
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
ts.requestMore(3);
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
}
});
}
}).buffer(5, 2).subscribe(ts);
assertEquals(9, requested.get());
ts.requestMore(3);
assertEquals(6, requested.get());
}
@Test
public void testProducerRequestThroughBufferWithSize4() {
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
}
});
}
}).buffer(5, 2).subscribe(ts);
assertEquals(Long.MAX_VALUE, requested.get());
}
@Test
public void testProducerRequestOverflowThroughBufferWithSize1() {
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
ts.requestMore(Long.MAX_VALUE / 2);
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
}
});
}
}).buffer(3, 3).subscribe(ts);
assertEquals(Long.MAX_VALUE, requested.get());
}
@Test
public void testProducerRequestOverflowThroughBufferWithSize2() {
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
ts.requestMore(Long.MAX_VALUE / 2);
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
}
});
}
}).buffer(3, 2).subscribe(ts);
assertEquals(Long.MAX_VALUE, requested.get());
}
@Test
public void testProducerRequestOverflowThroughBufferWithSize3() {
final AtomicLong requested = new AtomicLong();
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(final Subscriber<? super Integer> s) {
s.setProducer(new Producer() {
@Override
public void request(long n) {
requested.set(n);
s.onNext(1);
s.onNext(2);
s.onNext(3);
}
});
}
}).buffer(3, 2).subscribe(new Subscriber<List<Integer>>() {
@Override
public void onStart() {
request(Long.MAX_VALUE / 2 - 4);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<Integer> t) {
request(Long.MAX_VALUE / 2);
}
});
assertEquals(Long.MAX_VALUE, requested.get());
}
@Test(timeout = 3000)
public void testBufferWithTimeDoesntUnsubscribeDownstream() throws InterruptedException {
@SuppressWarnings("unchecked")
final Observer<Object> o = mock(Observer.class);
final CountDownLatch cdl = new CountDownLatch(1);
Subscriber<Object> s = new Subscriber<Object>() {
@Override
public void onNext(Object t) {
o.onNext(t);
}
@Override
public void onError(Throwable e) {
o.onError(e);
cdl.countDown();
}
@Override
public void onCompleted() {
o.onCompleted();
cdl.countDown();
}
};
Observable.range(1, 1).delay(1, TimeUnit.SECONDS).buffer(2, TimeUnit.SECONDS).unsafeSubscribe(s);
cdl.await();
verify(o).onNext(Arrays.asList(1));
verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
assertFalse(s.isUnsubscribed());
}
}