@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");
      }
    }
  }