/** * 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(); } }
@Ignore // FIXME throwing is not allowed from the create?! @Test public void testOnSubscribeFails() { Subscriber<String> observer = TestHelper.mockSubscriber(); final RuntimeException re = new RuntimeException("bad impl"); Observable<String> o = Observable.create( s -> { throw re; }); o.subscribe(observer); verify(observer, times(0)).onNext(anyString()); verify(observer, times(0)).onComplete(); verify(observer, times(1)).onError(re); }
@Test public void testRequestToObservable() { TestSubscriber<Integer> ts = new TestSubscriber<>(); ts.request(3); final AtomicLong requested = new AtomicLong(); Observable.<Integer>create( s -> s.onSubscribe( new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() {} })) .subscribe(ts); assertEquals(3, requested.get()); }
@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 testRequestThroughTakeWhereRequestIsSmallerThanTake() { TestSubscriber<Integer> ts = new TestSubscriber<>((Long) null); ts.request(3); final AtomicLong requested = new AtomicLong(); Observable.<Integer>create( s -> s.onSubscribe( new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() {} })) .take(10) .subscribe(ts); assertEquals(3, requested.get()); }
@Test public void testRequestThroughTakeThatReducesRequest() { TestSubscriber<Integer> ts = new TestSubscriber<>((Long) null); ts.request(3); final AtomicLong requested = new AtomicLong(); Observable.<Integer>create( s -> s.onSubscribe( new Subscription() { @Override public void request(long n) { requested.set(n); } @Override public void cancel() {} })) .take(2) .subscribe(ts); // FIXME the take now requests Long.MAX_PATH if downstream requests at least the limit assertEquals(Long.MAX_VALUE, requested.get()); }