@Test @SuppressWarnings("unchecked") public void testOrdering() throws InterruptedException { Observable<String> obs = Observable.just("one", null, "two", "three", "four"); Observer<String> observer = mock(Observer.class); InOrder inOrder = inOrder(observer); TestSubscriber<String> ts = new TestSubscriber<String>(observer); obs.observeOn(Schedulers.computation()).subscribe(ts); ts.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS); if (ts.getOnErrorEvents().size() > 0) { for (Throwable t : ts.getOnErrorEvents()) { t.printStackTrace(); } fail("failed with exception"); } inOrder.verify(observer, times(1)).onNext("one"); inOrder.verify(observer, times(1)).onNext(null); inOrder.verify(observer, times(1)).onNext("two"); inOrder.verify(observer, times(1)).onNext("three"); inOrder.verify(observer, times(1)).onNext("four"); inOrder.verify(observer, times(1)).onCompleted(); inOrder.verifyNoMoreInteractions(); }
/** * Make sure we get a MissingBackpressureException propagated through when we have a fast temporal * (hot) producer. */ @Test public void testHotOperatorBackpressure() { TestSubscriber<String> ts = new TestSubscriber<String>(); Observable.timer(0, 1, TimeUnit.MICROSECONDS) .observeOn(Schedulers.computation()) .map( new Func1<Long, String>() { @Override public String call(Long t1) { System.out.println(t1); try { Thread.sleep(100); } catch (InterruptedException e) { } return t1 + " slow value"; } }) .subscribe(ts); ts.awaitTerminalEvent(); System.out.println("Errors: " + ts.getOnErrorEvents()); assertEquals(1, ts.getOnErrorEvents().size()); assertEquals(MissingBackpressureException.class, ts.getOnErrorEvents().get(0).getClass()); }
@Test(timeout = 2000) public void testFirehoseFailsAsExpected() { AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); firehose(c).observeOn(Schedulers.computation()).map(SLOW_PASS_THRU).subscribe(ts); ts.awaitTerminalEvent(); System.out.println( "testFirehoseFailsAsExpected => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(1, ts.getOnErrorEvents().size()); assertTrue(ts.getOnErrorEvents().get(0) instanceof MissingBackpressureException); }
@Test public void testErrorPropagatesWhenNoOutstandingRequests() { Observable<Long> timer = Observable.timer(0, 1, TimeUnit.MICROSECONDS) .doOnEach( new Action1<Notification<? super Long>>() { @Override public void call(Notification<? super Long> n) { // System.out.println("BEFORE " + // n); } }) .observeOn(Schedulers.newThread()) .doOnEach( new Action1<Notification<? super Long>>() { @Override public void call(Notification<? super Long> n) { try { Thread.sleep(100); } catch (InterruptedException e) { } // System.out.println("AFTER " + // n); } }); TestSubscriber<Long> ts = new TestSubscriber<Long>(); Observable.combineLatest( timer, Observable.<Integer>never(), new Func2<Long, Integer, Long>() { @Override public Long call(Long t1, Integer t2) { return t1; } }) .take(RxRingBuffer.SIZE * 2) .subscribe(ts); ts.awaitTerminalEvent(); assertEquals(1, ts.getOnErrorEvents().size()); assertEquals(MissingBackpressureException.class, ts.getOnErrorEvents().get(0).getClass()); }
@Test public void testOnErrorCutsAheadOfOnNext() { final PublishSubject<Long> subject = PublishSubject.create(); final AtomicLong counter = new AtomicLong(); TestSubscriber<Long> ts = new TestSubscriber<Long>( new Observer<Long>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(Long t) { // simulate slow consumer to force backpressure failure try { Thread.sleep(1); } catch (InterruptedException e) { } } }); subject.observeOn(Schedulers.computation()).subscribe(ts); // this will blow up with backpressure while (counter.get() < 102400) { subject.onNext(counter.get()); counter.incrementAndGet(); } ts.awaitTerminalEvent(); assertEquals(1, ts.getOnErrorEvents().size()); assertTrue(ts.getOnErrorEvents().get(0) instanceof MissingBackpressureException); // assert that the values are sequential, that cutting in didn't allow skipping some but // emitting others. // example [0, 1, 2] not [0, 1, 4] assertTrue( ts.getOnNextEvents().size() == ts.getOnNextEvents().get(ts.getOnNextEvents().size() - 1) + 1); // we should emit the error without emitting the full buffer size assertTrue(ts.getOnNextEvents().size() < RxRingBuffer.SIZE); }
@Test public void testQueueFullEmitsError() { final CountDownLatch latch = new CountDownLatch(1); Observable<Integer> observable = Observable.create( new OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> o) { for (int i = 0; i < RxRingBuffer.SIZE + 10; i++) { o.onNext(i); } latch.countDown(); o.onCompleted(); } }); TestSubscriber<Integer> testSubscriber = new TestSubscriber<Integer>( new Observer<Integer>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(Integer t) { // force it to be slow and wait until we have queued everything try { latch.await(500, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }); observable.observeOn(Schedulers.newThread()).subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); List<Throwable> errors = testSubscriber.getOnErrorEvents(); assertEquals(1, errors.size()); System.out.println("Errors: " + errors); Throwable t = errors.get(0); if (t instanceof MissingBackpressureException) { // success, we expect this } else { if (t.getCause() instanceof MissingBackpressureException) { // this is also okay } else { fail("Expecting MissingBackpressureException"); } } }