@Test
  public void testMergeAsyncThenObserveOnLoop() {
    for (int i = 0; i < 500; i++) {
      if (i % 10 == 0) {
        System.out.println("testMergeAsyncThenObserveOnLoop >> " + i);
      }
      // Verify there is no MissingBackpressureException
      int NUM = (int) (Observable.bufferSize() * 4.1);
      AtomicInteger c1 = new AtomicInteger();
      AtomicInteger c2 = new AtomicInteger();

      TestSubscriber<Integer> ts = new TestSubscriber<>();
      Observable<Integer> merged =
          Observable.merge(
              incrementingIntegers(c1).subscribeOn(Schedulers.computation()),
              incrementingIntegers(c2).subscribeOn(Schedulers.computation()));

      merged.observeOn(Schedulers.io()).take(NUM).subscribe(ts);

      ts.awaitTerminalEvent(5, TimeUnit.SECONDS);
      ts.assertComplete();
      ts.assertNoErrors();
      System.out.println(
          "testMergeAsyncThenObserveOn => Received: "
              + ts.valueCount()
              + "  Emitted: "
              + c1.get()
              + " / "
              + c2.get());
      assertEquals(NUM, ts.valueCount());
    }
  }
  @Test
  public void testMergeAsyncThenObserveOn() {
    int NUM = (int) (Observable.bufferSize() * 4.1);
    AtomicInteger c1 = new AtomicInteger();
    AtomicInteger c2 = new AtomicInteger();
    TestSubscriber<Integer> ts = new TestSubscriber<>();
    Observable<Integer> merged =
        Observable.merge(
            incrementingIntegers(c1).subscribeOn(Schedulers.computation()),
            incrementingIntegers(c2).subscribeOn(Schedulers.computation()));

    merged.observeOn(Schedulers.newThread()).take(NUM).subscribe(ts);
    ts.awaitTerminalEvent();
    ts.assertNoErrors();
    System.out.println(
        "testMergeAsyncThenObserveOn => Received: "
            + ts.valueCount()
            + "  Emitted: "
            + c1.get()
            + " / "
            + c2.get());
    assertEquals(NUM, ts.valueCount());
    // either one can starve the other, but neither should be capable of doing more than 5 batches
    // (taking 4.1)
    // TODO is it possible to make this deterministic rather than one possibly starving the other?
    // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair"
    // algoritms generally take a performance hit
    // akarnokd => run this in a loop over 10k times and never saw values get as high as 7*SIZE, but
    // since observeOn delays the unsubscription non-deterministically, the test will remain
    // unreliable
    assertTrue(c1.get() < Observable.bufferSize() * 7);
    assertTrue(c2.get() < Observable.bufferSize() * 7);
  }
  @Test
  public void testMergeAsync() {
    int NUM = (int) (Observable.bufferSize() * 4.1);
    AtomicInteger c1 = new AtomicInteger();
    AtomicInteger c2 = new AtomicInteger();
    TestSubscriber<Integer> ts = new TestSubscriber<>();
    Observable<Integer> merged =
        Observable.merge(
            incrementingIntegers(c1).subscribeOn(Schedulers.computation()),
            incrementingIntegers(c2).subscribeOn(Schedulers.computation()));

    merged.take(NUM).subscribe(ts);
    ts.awaitTerminalEvent();
    ts.assertNoErrors();
    System.out.println(
        "testMergeAsync => Received: "
            + ts.valueCount()
            + "  Emitted: "
            + c1.get()
            + " / "
            + c2.get());
    assertEquals(NUM, ts.valueCount());
    // either one can starve the other, but neither should be capable of doing more than 5 batches
    // (taking 4.1)
    // TODO is it possible to make this deterministic rather than one possibly starving the other?
    // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair"
    // algoritms generally take a performance hit
    int max = Observable.bufferSize() * 7;
    assertTrue("" + c1.get() + " >= " + max, c1.get() < max);
    assertTrue("" + c2.get() + " >= " + max, c2.get() < max);
  }