/** * https://github.com/ReactiveX/RxJava/issues/198 * * <p>Rx Design Guidelines 5.2 * * <p>"when calling the Subscribe method that only has an onNext argument, the OnError behavior * will be to rethrow the exception on the thread that the message comes out from the Observable. * The OnCompleted behavior in this case is to do nothing." * * @throws InterruptedException */ @Test @Ignore("Subscribers can't throw") public void testErrorThrownWithoutErrorHandlerAsynchronous() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<Throwable> exception = new AtomicReference<>(); Observable.create( observer -> { new Thread( () -> { try { observer.onError(new Error("failure")); } catch (Throwable e) { // without an onError handler it has to just throw on whatever thread // invokes it exception.set(e); } latch.countDown(); }) .start(); }) .subscribe(); // wait for exception latch.await(3000, TimeUnit.MILLISECONDS); assertNotNull(exception.get()); assertEquals("failure", exception.get().getMessage()); }
@Test public void testPublishLast() throws InterruptedException { final AtomicInteger count = new AtomicInteger(); ConnectableObservable<String> connectable = Observable.<String>create( observer -> { observer.onSubscribe(EmptySubscription.INSTANCE); count.incrementAndGet(); new Thread( () -> { observer.onNext("first"); observer.onNext("last"); observer.onComplete(); }) .start(); }) .takeLast(1) .publish(); // subscribe once final CountDownLatch latch = new CountDownLatch(1); connectable.subscribe( value -> { assertEquals("last", value); latch.countDown(); }); // subscribe twice connectable.subscribe(); Disposable subscription = connectable.connect(); assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); assertEquals(1, count.get()); subscription.dispose(); }
@Test public void testReplay() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); ConnectableObservable<String> o = Observable.<String>create( observer -> { observer.onSubscribe(EmptySubscription.INSTANCE); new Thread( new Runnable() { @Override public void run() { counter.incrementAndGet(); observer.onNext("one"); observer.onComplete(); } }) .start(); }) .replay(); // we connect immediately and it will emit the value Disposable s = o.connect(); try { // we then expect the following 2 subscriptions to get that same value final CountDownLatch latch = new CountDownLatch(2); // subscribe once o.subscribe( v -> { assertEquals("one", v); latch.countDown(); }); // subscribe again o.subscribe( v -> { assertEquals("one", v); latch.countDown(); }); if (!latch.await(1000, TimeUnit.MILLISECONDS)) { fail("subscriptions did not receive values"); } assertEquals(1, counter.get()); } finally { s.dispose(); } }
/** * The error from the user provided Observer is not handled by the subscribe method try/catch. * * <p>It is handled by the AtomicObserver that wraps the provided Observer. * * <p>Result: Passes (if AtomicObserver functionality exists) */ @Test public void testCustomObservableWithErrorInObserverAsynchronous() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); // FIXME custom built??? Observable.just("1", "2", "three", "4") .subscribeOn(Schedulers.newThread()) .safeSubscribe( new Observer<String>() { @Override public void onComplete() { System.out.println("completed"); latch.countDown(); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); latch.countDown(); } @Override public void onNext(String v) { int num = Integer.parseInt(v); System.out.println(num); // doSomething(num); count.incrementAndGet(); } }); // wait for async sequence to complete latch.await(); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } }
@Test public void testCacheWithCapacity() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); Observable<String> o = Observable.<String>create( observer -> { observer.onSubscribe(EmptySubscription.INSTANCE); new Thread( () -> { counter.incrementAndGet(); observer.onNext("one"); observer.onComplete(); }) .start(); }) .cache(1); // we then expect the following 2 subscriptions to get that same value final CountDownLatch latch = new CountDownLatch(2); // subscribe once o.subscribe( v -> { assertEquals("one", v); latch.countDown(); }); // subscribe again o.subscribe( v -> { assertEquals("one", v); latch.countDown(); }); if (!latch.await(1000, TimeUnit.MILLISECONDS)) { fail("subscriptions did not receive values"); } assertEquals(1, counter.get()); }
@Test public void testUserSubscriberUsingRequestAsync() throws InterruptedException { AtomicInteger c = new AtomicInteger(); final AtomicInteger totalReceived = new AtomicInteger(); final AtomicInteger received = new AtomicInteger(); final AtomicInteger batches = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(1); incrementingIntegers(c) .subscribeOn(Schedulers.newThread()) .subscribe( new AsyncObserver<Integer>() { @Override public void onStart() { request(100); } @Override public void onComplete() { latch.countDown(); } @Override public void onError(Throwable e) { latch.countDown(); } @Override public void onNext(Integer t) { int total = totalReceived.incrementAndGet(); received.incrementAndGet(); boolean done = false; if (total >= 2000) { done = true; cancel(); } if (received.get() == 100) { batches.incrementAndGet(); received.set(0); if (!done) { request(100); } } if (done) { latch.countDown(); } } }); latch.await(); System.out.println( "testUserSubscriberUsingRequestAsync => Received: " + totalReceived.get() + " Emitted: " + c.get() + " Request Batches: " + batches.get()); assertEquals(2000, c.get()); assertEquals(2000, totalReceived.get()); assertEquals(20, batches.get()); }