diff --git a/src/main/java/io/reactivex/internal/operators/completable/CompletableMerge.java b/src/main/java/io/reactivex/internal/operators/completable/CompletableMerge.java index a1dff5b342..a052c72bd6 100644 --- a/src/main/java/io/reactivex/internal/operators/completable/CompletableMerge.java +++ b/src/main/java/io/reactivex/internal/operators/completable/CompletableMerge.java @@ -70,6 +70,7 @@ static final class CompletableMergeSubscriber public void dispose() { upstream.cancel(); set.dispose(); + error.tryTerminateAndReport(); } @Override @@ -106,7 +107,7 @@ public void onError(Throwable t) { if (error.addThrowable(t)) { if (getAndSet(0) > 0) { - downstream.onError(error.terminate()); + error.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(t); @@ -114,7 +115,7 @@ public void onError(Throwable t) { } else { if (error.addThrowable(t)) { if (decrementAndGet() == 0) { - downstream.onError(error.terminate()); + error.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(t); @@ -125,12 +126,7 @@ public void onError(Throwable t) { @Override public void onComplete() { if (decrementAndGet() == 0) { - Throwable ex = error.get(); - if (ex != null) { - downstream.onError(error.terminate()); - } else { - downstream.onComplete(); - } + error.tryTerminateConsumer(downstream); } } @@ -142,7 +138,7 @@ void innerError(MergeInnerObserver inner, Throwable t) { if (error.addThrowable(t)) { if (getAndSet(0) > 0) { - downstream.onError(error.terminate()); + error.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(t); @@ -150,7 +146,7 @@ void innerError(MergeInnerObserver inner, Throwable t) { } else { if (error.addThrowable(t)) { if (decrementAndGet() == 0) { - downstream.onError(error.terminate()); + error.tryTerminateConsumer(downstream); } else { if (maxConcurrency != Integer.MAX_VALUE) { upstream.request(1); @@ -165,12 +161,7 @@ void innerError(MergeInnerObserver inner, Throwable t) { void innerComplete(MergeInnerObserver inner) { set.delete(inner); if (decrementAndGet() == 0) { - Throwable ex = error.get(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + error.tryTerminateConsumer(downstream); } else { if (maxConcurrency != Integer.MAX_VALUE) { upstream.request(1); diff --git a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeArray.java b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeArray.java index e6a42b105b..81185866cc 100644 --- a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeArray.java +++ b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeArray.java @@ -32,7 +32,7 @@ public void subscribeActual(final CompletableObserver observer) { final AtomicBoolean once = new AtomicBoolean(); InnerCompletableObserver shared = new InnerCompletableObserver(observer, once, set, sources.length + 1); - observer.onSubscribe(set); + observer.onSubscribe(shared); for (CompletableSource c : sources) { if (set.isDisposed()) { @@ -52,7 +52,7 @@ public void subscribeActual(final CompletableObserver observer) { shared.onComplete(); } - static final class InnerCompletableObserver extends AtomicInteger implements CompletableObserver { + static final class InnerCompletableObserver extends AtomicInteger implements CompletableObserver, Disposable { private static final long serialVersionUID = -8360547806504310570L; final CompletableObserver downstream; @@ -91,5 +91,16 @@ public void onComplete() { } } } + + @Override + public void dispose() { + set.dispose(); + once.set(true); + } + + @Override + public boolean isDisposed() { + return set.isDisposed(); + } } } diff --git a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorArray.java b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorArray.java index c2508a46dd..5629d9db4a 100644 --- a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorArray.java +++ b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorArray.java @@ -34,6 +34,7 @@ public void subscribeActual(final CompletableObserver observer) { final AtomicInteger wip = new AtomicInteger(sources.length + 1); final AtomicThrowable error = new AtomicThrowable(); + set.add(new TryTerminateAndReportDisposable(error)); observer.onSubscribe(set); @@ -53,12 +54,24 @@ public void subscribeActual(final CompletableObserver observer) { } if (wip.decrementAndGet() == 0) { - Throwable ex = error.terminate(); - if (ex == null) { - observer.onComplete(); - } else { - observer.onError(ex); - } + error.tryTerminateConsumer(observer); + } + } + + static final class TryTerminateAndReportDisposable implements Disposable { + final AtomicThrowable errors; + TryTerminateAndReportDisposable(AtomicThrowable errors) { + this.errors = errors; + } + + @Override + public void dispose() { + errors.tryTerminateAndReport(); + } + + @Override + public boolean isDisposed() { + return errors.isTerminated(); } } @@ -98,12 +111,7 @@ public void onComplete() { void tryTerminate() { if (wip.decrementAndGet() == 0) { - Throwable ex = error.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + error.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorIterable.java b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorIterable.java index 40c84d1176..e6192a4e84 100644 --- a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorIterable.java +++ b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeDelayErrorIterable.java @@ -20,7 +20,7 @@ import io.reactivex.disposables.CompositeDisposable; import io.reactivex.exceptions.Exceptions; import io.reactivex.internal.functions.ObjectHelper; -import io.reactivex.internal.operators.completable.CompletableMergeDelayErrorArray.MergeInnerCompletableObserver; +import io.reactivex.internal.operators.completable.CompletableMergeDelayErrorArray.*; import io.reactivex.internal.util.AtomicThrowable; public final class CompletableMergeDelayErrorIterable extends Completable { @@ -50,6 +50,7 @@ public void subscribeActual(final CompletableObserver observer) { final AtomicInteger wip = new AtomicInteger(1); final AtomicThrowable error = new AtomicThrowable(); + set.add(new TryTerminateAndReportDisposable(error)); for (;;) { if (set.isDisposed()) { @@ -93,12 +94,7 @@ public void subscribeActual(final CompletableObserver observer) { } if (wip.decrementAndGet() == 0) { - Throwable ex = error.terminate(); - if (ex == null) { - observer.onComplete(); - } else { - observer.onError(ex); - } + error.tryTerminateConsumer(observer); } } } diff --git a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeIterable.java b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeIterable.java index 0130250225..7c3cea6737 100644 --- a/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeIterable.java +++ b/src/main/java/io/reactivex/internal/operators/completable/CompletableMergeIterable.java @@ -32,8 +32,11 @@ public CompletableMergeIterable(Iterable sources) { @Override public void subscribeActual(final CompletableObserver observer) { final CompositeDisposable set = new CompositeDisposable(); + final AtomicInteger wip = new AtomicInteger(1); + + MergeCompletableObserver shared = new MergeCompletableObserver(observer, set, wip); - observer.onSubscribe(set); + observer.onSubscribe(shared); Iterator iterator; @@ -45,9 +48,6 @@ public void subscribeActual(final CompletableObserver observer) { return; } - final AtomicInteger wip = new AtomicInteger(1); - - MergeCompletableObserver shared = new MergeCompletableObserver(observer, set, wip); for (;;) { if (set.isDisposed()) { return; @@ -94,7 +94,7 @@ public void subscribeActual(final CompletableObserver observer) { shared.onComplete(); } - static final class MergeCompletableObserver extends AtomicBoolean implements CompletableObserver { + static final class MergeCompletableObserver extends AtomicBoolean implements CompletableObserver, Disposable { private static final long serialVersionUID = -7730517613164279224L; @@ -133,5 +133,16 @@ public void onComplete() { } } } + + @Override + public void dispose() { + set.dispose(); + set(true); + } + + @Override + public boolean isDisposed() { + return set.isDisposed(); + } } } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMap.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMap.java index 6a768c71f4..176ca803ec 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMap.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMap.java @@ -200,7 +200,7 @@ public void onError(Throwable t) { inner.cancel(); if (getAndIncrement() == 0) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(t); @@ -214,7 +214,7 @@ public void innerNext(R value) { if (compareAndSet(1, 0)) { return; } - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); } } @@ -224,7 +224,7 @@ public void innerError(Throwable e) { upstream.cancel(); if (getAndIncrement() == 0) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(e); @@ -243,6 +243,8 @@ public void cancel() { inner.cancel(); upstream.cancel(); + + errors.tryTerminateAndReport(); } } @@ -265,7 +267,7 @@ void drain() { Exceptions.throwIfFatal(e); upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -286,7 +288,7 @@ void drain() { upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -312,7 +314,7 @@ void drain() { Exceptions.throwIfFatal(e); upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -324,7 +326,7 @@ void drain() { if (get() == 0 && compareAndSet(0, 1)) { downstream.onNext(vr); if (!compareAndSet(1, 0)) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -437,6 +439,8 @@ public void cancel() { inner.cancel(); upstream.cancel(); + + errors.tryTerminateAndReport(); } } @@ -456,7 +460,7 @@ void drain() { if (d && !veryEnd) { Throwable ex = errors.get(); if (ex != null) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -468,20 +472,18 @@ void drain() { } catch (Throwable e) { Exceptions.throwIfFatal(e); upstream.cancel(); - errors.addThrowable(e); - downstream.onError(errors.terminate()); + if (errors.addThrowable(e)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(e); + } return; } boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } @@ -495,7 +497,7 @@ void drain() { upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -522,7 +524,7 @@ void drain() { errors.addThrowable(e); if (!veryEnd) { upstream.cancel(); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } vr = null; diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEager.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEager.java index 8acad8ac69..9376833326 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEager.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEager.java @@ -163,6 +163,7 @@ public void cancel() { } cancelled = true; upstream.cancel(); + errors.tryTerminateAndReport(); drainAndCancel(); } @@ -247,7 +248,7 @@ public void drain() { if (ex != null) { cancelAll(); - a.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -257,12 +258,7 @@ public void drain() { inner = subscribers.poll(); if (outerDone && inner == null) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } @@ -289,7 +285,7 @@ public void drain() { inner.cancel(); cancelAll(); - a.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -343,7 +339,7 @@ public void drain() { inner.cancel(); cancelAll(); - a.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); return; } } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapScheduler.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapScheduler.java index 8b55a5b9d5..f3d6eb2258 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapScheduler.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableConcatMapScheduler.java @@ -199,7 +199,7 @@ public void onError(Throwable t) { inner.cancel(); if (getAndIncrement() == 0) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); } } else { @@ -214,7 +214,7 @@ public void innerNext(R value) { if (compareAndSet(1, 0)) { return; } - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); } } @@ -225,7 +225,7 @@ public void innerError(Throwable e) { upstream.cancel(); if (getAndIncrement() == 0) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); } } else { @@ -246,6 +246,7 @@ public void cancel() { inner.cancel(); upstream.cancel(); worker.dispose(); + errors.tryTerminateAndReport(); } } @@ -274,7 +275,7 @@ public void run() { Exceptions.throwIfFatal(e); upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -297,7 +298,7 @@ public void run() { upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -324,7 +325,7 @@ public void run() { Exceptions.throwIfFatal(e); upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -337,7 +338,7 @@ public void run() { if (get() == 0 && compareAndSet(0, 1)) { downstream.onNext(vr); if (!compareAndSet(1, 0)) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -425,6 +426,7 @@ public void cancel() { inner.cancel(); upstream.cancel(); worker.dispose(); + errors.tryTerminateAndReport(); } } @@ -450,7 +452,7 @@ public void run() { if (d && !veryEnd) { Throwable ex = errors.get(); if (ex != null) { - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -464,7 +466,7 @@ public void run() { Exceptions.throwIfFatal(e); upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -472,12 +474,7 @@ public void run() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -492,7 +489,7 @@ public void run() { upstream.cancel(); errors.addThrowable(e); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -520,7 +517,7 @@ public void run() { errors.addThrowable(e); if (!veryEnd) { upstream.cancel(); - downstream.onError(errors.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMap.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMap.java index 52dd347b4b..23d490cf69 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMap.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMap.java @@ -72,7 +72,7 @@ static final class MergeSubscriber extends AtomicInteger implements Flowab volatile boolean done; - final AtomicThrowable errs = new AtomicThrowable(); + final AtomicThrowable errors = new AtomicThrowable(); volatile boolean cancelled; @@ -142,7 +142,7 @@ public void onNext(T t) { u = ((Supplier)p).get(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); - errs.addThrowable(ex); + errors.addThrowable(ex); drain(); return; } @@ -319,7 +319,7 @@ public void onError(Throwable t) { RxJavaPlugins.onError(t); return; } - if (errs.addThrowable(t)) { + if (errors.addThrowable(t)) { done = true; drain(); } else { @@ -419,14 +419,7 @@ void drainLoop() { int n = inner.length; if (d && (svq == null || svq.isEmpty()) && n == 0) { - Throwable ex = errs.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - if (ex == null) { - child.onComplete(); - } else { - child.onError(ex); - } - } + errors.tryTerminateConsumer(downstream); return; } @@ -481,7 +474,7 @@ void drainLoop() { } catch (Throwable ex) { Exceptions.throwIfFatal(ex); is.dispose(); - errs.addThrowable(ex); + errors.addThrowable(ex); if (!delayErrors) { upstream.cancel(); } @@ -559,12 +552,9 @@ boolean checkTerminate() { clearScalarQueue(); return true; } - if (!delayErrors && errs.get() != null) { + if (!delayErrors && errors.get() != null) { clearScalarQueue(); - Throwable ex = errs.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); return true; } return false; @@ -585,13 +575,13 @@ void disposeAll() { for (InnerSubscriber inner : a) { inner.dispose(); } - errs.tryTerminateAndReport(); + errors.tryTerminateAndReport(); } } } void innerError(InnerSubscriber inner, Throwable t) { - if (errs.addThrowable(t)) { + if (errors.addThrowable(t)) { inner.done = true; if (!delayErrors) { upstream.cancel(); diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletable.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletable.java index 86311bc27d..f2661e43b4 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletable.java @@ -129,18 +129,18 @@ public void onError(Throwable e) { if (errors.addThrowable(e)) { if (delayErrors) { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } else { if (maxConcurrency != Integer.MAX_VALUE) { upstream.request(1); } } } else { - cancel(); + cancelled = true; + upstream.cancel(); + set.dispose(); if (getAndSet(0) > 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } } else { @@ -151,12 +151,7 @@ public void onError(Throwable e) { @Override public void onComplete() { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); } else { if (maxConcurrency != Integer.MAX_VALUE) { upstream.request(1); @@ -169,6 +164,7 @@ public void cancel() { cancelled = true; upstream.cancel(); set.dispose(); + errors.tryTerminateAndReport(); } @Override diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java index ad5434273b..1a2eafc299 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java @@ -136,18 +136,18 @@ public void onError(Throwable e) { if (errors.addThrowable(e)) { if (delayErrors) { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } else { if (maxConcurrency != Integer.MAX_VALUE) { upstream.request(1); } } } else { - dispose(); + disposed = true; + upstream.cancel(); + set.dispose(); if (getAndSet(0) > 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } } else { @@ -158,12 +158,7 @@ public void onError(Throwable e) { @Override public void onComplete() { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); } else { if (maxConcurrency != Integer.MAX_VALUE) { upstream.request(1); @@ -176,6 +171,7 @@ public void dispose() { disposed = true; upstream.cancel(); set.dispose(); + errors.tryTerminateAndReport(); } @Override diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybe.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybe.java index ab2950e2a3..aa46b7acd5 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybe.java @@ -157,6 +157,7 @@ public void cancel() { cancelled = true; upstream.cancel(); set.dispose(); + errors.tryTerminateAndReport(); } @Override @@ -177,12 +178,7 @@ void innerSuccess(InnerObserver inner, R value) { SpscLinkedArrayQueue q = queue.get(); if (d && (q == null || q.isEmpty())) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } BackpressureHelper.produced(requested, 1); @@ -250,12 +246,7 @@ void innerComplete(InnerObserver inner) { SpscLinkedArrayQueue q = queue.get(); if (d && (q == null || q.isEmpty())) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } @@ -307,9 +298,8 @@ void drainLoop() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - ex = errors.terminate(); clear(); - a.onError(ex); + errors.tryTerminateConsumer(a); return; } } @@ -320,12 +310,7 @@ void drainLoop() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } @@ -347,9 +332,8 @@ void drainLoop() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - ex = errors.terminate(); clear(); - a.onError(ex); + errors.tryTerminateConsumer(a); return; } } @@ -359,12 +343,7 @@ void drainLoop() { boolean empty = q == null || q.isEmpty(); if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingle.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingle.java index 0633248d8c..9513736025 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingle.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingle.java @@ -157,6 +157,7 @@ public void cancel() { cancelled = true; upstream.cancel(); set.dispose(); + errors.tryTerminateAndReport(); } @Override @@ -177,12 +178,7 @@ void innerSuccess(InnerObserver inner, R value) { SpscLinkedArrayQueue q = queue.get(); if (d && (q == null || q.isEmpty())) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } BackpressureHelper.produced(requested, 1); @@ -274,9 +270,8 @@ void drainLoop() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - ex = errors.terminate(); clear(); - a.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -287,12 +282,7 @@ void drainLoop() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } @@ -314,9 +304,8 @@ void drainLoop() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - ex = errors.terminate(); clear(); - a.onError(ex); + errors.tryTerminateConsumer(a); return; } } @@ -326,12 +315,7 @@ void drainLoop() { boolean empty = q == null || q.isEmpty(); if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletable.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletable.java index c65386bbb1..435b604b63 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletable.java @@ -58,7 +58,7 @@ static final class MergeWithSubscriber extends AtomicInteger final OtherObserver otherObserver; - final AtomicThrowable error; + final AtomicThrowable errors; final AtomicLong requested; @@ -70,7 +70,7 @@ static final class MergeWithSubscriber extends AtomicInteger this.downstream = downstream; this.mainSubscription = new AtomicReference(); this.otherObserver = new OtherObserver(this); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); this.requested = new AtomicLong(); } @@ -81,20 +81,20 @@ public void onSubscribe(Subscription s) { @Override public void onNext(T t) { - HalfSerializer.onNext(downstream, t, this, error); + HalfSerializer.onNext(downstream, t, this, errors); } @Override public void onError(Throwable ex) { DisposableHelper.dispose(otherObserver); - HalfSerializer.onError(downstream, ex, this, error); + HalfSerializer.onError(downstream, ex, this, errors); } @Override public void onComplete() { mainDone = true; if (otherDone) { - HalfSerializer.onComplete(downstream, this, error); + HalfSerializer.onComplete(downstream, this, errors); } } @@ -107,17 +107,18 @@ public void request(long n) { public void cancel() { SubscriptionHelper.cancel(mainSubscription); DisposableHelper.dispose(otherObserver); + errors.tryTerminateAndReport(); } void otherError(Throwable ex) { SubscriptionHelper.cancel(mainSubscription); - HalfSerializer.onError(downstream, ex, this, error); + HalfSerializer.onError(downstream, ex, this, errors); } void otherComplete() { otherDone = true; if (mainDone) { - HalfSerializer.onComplete(downstream, this, error); + HalfSerializer.onComplete(downstream, this, errors); } } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybe.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybe.java index 1787d5fce3..8cd1c81220 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybe.java @@ -61,7 +61,7 @@ static final class MergeWithObserver extends AtomicInteger final OtherObserver otherObserver; - final AtomicThrowable error; + final AtomicThrowable errors; final AtomicLong requested; @@ -91,7 +91,7 @@ static final class MergeWithObserver extends AtomicInteger this.downstream = downstream; this.mainSubscription = new AtomicReference(); this.otherObserver = new OtherObserver(this); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); this.requested = new AtomicLong(); this.prefetch = bufferSize(); this.limit = prefetch - (prefetch >> 2); @@ -142,7 +142,7 @@ public void onNext(T t) { @Override public void onError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { DisposableHelper.dispose(otherObserver); drain(); } else { @@ -167,6 +167,7 @@ public void cancel() { cancelled = true; SubscriptionHelper.cancel(mainSubscription); DisposableHelper.dispose(otherObserver); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue = null; singleItem = null; @@ -199,7 +200,7 @@ void otherSuccess(T value) { } void otherError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { SubscriptionHelper.cancel(mainSubscription); drain(); } else { @@ -244,10 +245,10 @@ void drainLoop() { return; } - if (error.get() != null) { + if (errors.get() != null) { singleItem = null; queue = null; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -295,10 +296,10 @@ void drainLoop() { return; } - if (error.get() != null) { + if (errors.get() != null) { singleItem = null; queue = null; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingle.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingle.java index 486cb73f8c..c27a90e594 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingle.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingle.java @@ -61,7 +61,7 @@ static final class MergeWithObserver extends AtomicInteger final OtherObserver otherObserver; - final AtomicThrowable error; + final AtomicThrowable errors; final AtomicLong requested; @@ -91,7 +91,7 @@ static final class MergeWithObserver extends AtomicInteger this.downstream = downstream; this.mainSubscription = new AtomicReference(); this.otherObserver = new OtherObserver(this); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); this.requested = new AtomicLong(); this.prefetch = bufferSize(); this.limit = prefetch - (prefetch >> 2); @@ -142,7 +142,7 @@ public void onNext(T t) { @Override public void onError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { DisposableHelper.dispose(otherObserver); drain(); } else { @@ -167,6 +167,7 @@ public void cancel() { cancelled = true; SubscriptionHelper.cancel(mainSubscription); DisposableHelper.dispose(otherObserver); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue = null; singleItem = null; @@ -199,7 +200,7 @@ void otherSuccess(T value) { } void otherError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { SubscriptionHelper.cancel(mainSubscription); drain(); } else { @@ -239,10 +240,10 @@ void drainLoop() { return; } - if (error.get() != null) { + if (errors.get() != null) { singleItem = null; queue = null; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -290,10 +291,10 @@ void drainLoop() { return; } - if (error.get() != null) { + if (errors.get() != null) { singleItem = null; queue = null; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqual.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqual.java index fd10367248..237546a75b 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqual.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqual.java @@ -68,7 +68,7 @@ static final class EqualCoordinator extends DeferredScalarSubscription second; - final AtomicThrowable error; + final AtomicThrowable errors; final AtomicInteger wip; @@ -82,7 +82,7 @@ static final class EqualCoordinator extends DeferredScalarSubscription(this, prefetch); this.second = new EqualSubscriber(this, prefetch); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); } void subscribe(Publisher source1, Publisher source2) { @@ -95,6 +95,7 @@ public void cancel() { super.cancel(); first.cancel(); second.cancel(); + errors.tryTerminateAndReport(); if (wip.getAndIncrement() == 0) { first.clear(); second.clear(); @@ -128,11 +129,11 @@ public void drain() { return; } - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { cancelAndClear(); - downstream.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -145,8 +146,11 @@ public void drain() { } catch (Throwable exc) { Exceptions.throwIfFatal(exc); cancelAndClear(); - error.addThrowable(exc); - downstream.onError(error.terminate()); + if (errors.addThrowable(exc)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(exc); + } return; } v1 = a; @@ -161,8 +165,11 @@ public void drain() { } catch (Throwable exc) { Exceptions.throwIfFatal(exc); cancelAndClear(); - error.addThrowable(exc); - downstream.onError(error.terminate()); + if (errors.addThrowable(exc)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(exc); + } return; } v2 = b; @@ -191,8 +198,8 @@ public void drain() { } catch (Throwable exc) { Exceptions.throwIfFatal(exc); cancelAndClear(); - error.addThrowable(exc); - downstream.onError(error.terminate()); + errors.addThrowable(exc); + errors.tryTerminateConsumer(downstream); return; } @@ -216,11 +223,11 @@ public void drain() { return; } - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { cancelAndClear(); - downstream.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -234,7 +241,7 @@ public void drain() { @Override public void innerError(Throwable t) { - if (error.addThrowable(t)) { + if (errors.addThrowable(t)) { drain(); } else { RxJavaPlugins.onError(t); diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualSingle.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualSingle.java index bcda903c85..5c53d8283a 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualSingle.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualSingle.java @@ -67,7 +67,7 @@ static final class EqualCoordinator final EqualSubscriber second; - final AtomicThrowable error; + final AtomicThrowable errors; T v1; @@ -78,7 +78,7 @@ static final class EqualCoordinator this.comparer = comparer; this.first = new EqualSubscriber(this, prefetch); this.second = new EqualSubscriber(this, prefetch); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); } void subscribe(Publisher source1, Publisher source2) { @@ -90,6 +90,7 @@ void subscribe(Publisher source1, Publisher source2) { public void dispose() { first.cancel(); second.cancel(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { first.clear(); second.clear(); @@ -128,11 +129,11 @@ public void drain() { return; } - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { cancelAndClear(); - downstream.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } @@ -145,8 +146,11 @@ public void drain() { } catch (Throwable exc) { Exceptions.throwIfFatal(exc); cancelAndClear(); - error.addThrowable(exc); - downstream.onError(error.terminate()); + if (errors.addThrowable(exc)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(exc); + } return; } v1 = a; @@ -161,8 +165,11 @@ public void drain() { } catch (Throwable exc) { Exceptions.throwIfFatal(exc); cancelAndClear(); - error.addThrowable(exc); - downstream.onError(error.terminate()); + if (errors.addThrowable(exc)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(exc); + } return; } v2 = b; @@ -191,8 +198,8 @@ public void drain() { } catch (Throwable exc) { Exceptions.throwIfFatal(exc); cancelAndClear(); - error.addThrowable(exc); - downstream.onError(error.terminate()); + errors.addThrowable(exc); + errors.tryTerminateConsumer(downstream); return; } @@ -216,11 +223,11 @@ public void drain() { return; } - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { cancelAndClear(); - downstream.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -234,7 +241,7 @@ public void drain() { @Override public void innerError(Throwable t) { - if (error.addThrowable(t)) { + if (errors.addThrowable(t)) { drain(); } else { RxJavaPlugins.onError(t); diff --git a/src/main/java/io/reactivex/internal/operators/flowable/FlowableSwitchMap.java b/src/main/java/io/reactivex/internal/operators/flowable/FlowableSwitchMap.java index 146ee3f413..1a337c1066 100644 --- a/src/main/java/io/reactivex/internal/operators/flowable/FlowableSwitchMap.java +++ b/src/main/java/io/reactivex/internal/operators/flowable/FlowableSwitchMap.java @@ -58,7 +58,7 @@ static final class SwitchMapSubscriber extends AtomicInteger implements Fl final boolean delayErrors; volatile boolean done; - final AtomicThrowable error; + final AtomicThrowable errors; volatile boolean cancelled; @@ -83,7 +83,7 @@ static final class SwitchMapSubscriber extends AtomicInteger implements Fl this.mapper = mapper; this.bufferSize = bufferSize; this.delayErrors = delayErrors; - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); } @Override @@ -134,7 +134,7 @@ public void onNext(T t) { @Override public void onError(Throwable t) { - if (!done && error.addThrowable(t)) { + if (!done && errors.addThrowable(t)) { if (!delayErrors) { disposeInner(); } @@ -174,7 +174,7 @@ public void cancel() { disposeInner(); - error.tryTerminateAndReport(); + errors.tryTerminateAndReport(); } } @@ -208,19 +208,14 @@ void drain() { if (done) { if (delayErrors) { if (active.get() == null) { - Throwable err = error.get(); - if (err != null) { - a.onError(error.terminate()); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } } else { - Throwable err = error.get(); + Throwable err = errors.get(); if (err != null) { disposeInner(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(a); return; } else if (active.get() == null) { @@ -235,10 +230,10 @@ void drain() { if (q != null) { if (inner.done) { if (!delayErrors) { - Throwable err = error.get(); + Throwable err = errors.get(); if (err != null) { disposeInner(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(a); return; } else if (q.isEmpty()) { @@ -270,7 +265,7 @@ void drain() { } catch (Throwable ex) { Exceptions.throwIfFatal(ex); inner.cancel(); - error.addThrowable(ex); + errors.addThrowable(ex); d = true; v = null; } @@ -283,9 +278,9 @@ void drain() { if (d) { if (!delayErrors) { - Throwable err = error.get(); + Throwable err = errors.get(); if (err != null) { - a.onError(error.terminate()); + errors.tryTerminateConsumer(a); return; } else if (empty) { @@ -397,7 +392,7 @@ public void onNext(R t) { @Override public void onError(Throwable t) { SwitchMapSubscriber p = parent; - if (index == p.unique && p.error.addThrowable(t)) { + if (index == p.unique && p.errors.addThrowable(t)) { if (!p.delayErrors) { p.upstream.cancel(); } diff --git a/src/main/java/io/reactivex/internal/operators/maybe/MaybeConcatArrayDelayError.java b/src/main/java/io/reactivex/internal/operators/maybe/MaybeConcatArrayDelayError.java index 6c2e1604ab..3118ea30bf 100644 --- a/src/main/java/io/reactivex/internal/operators/maybe/MaybeConcatArrayDelayError.java +++ b/src/main/java/io/reactivex/internal/operators/maybe/MaybeConcatArrayDelayError.java @@ -87,6 +87,7 @@ public void request(long n) { @Override public void cancel() { disposables.dispose(); + errors.tryTerminateAndReport(); } @Override @@ -155,12 +156,7 @@ void drain() { if (goNextSource && !cancelled.isDisposed()) { int i = index; if (i == sources.length) { - Throwable ex = errors.get(); - if (ex != null) { - a.onError(errors.terminate()); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } index = i + 1; diff --git a/src/main/java/io/reactivex/internal/operators/maybe/MaybeMergeArray.java b/src/main/java/io/reactivex/internal/operators/maybe/MaybeMergeArray.java index 1edfdd69da..c0f5a89cbf 100644 --- a/src/main/java/io/reactivex/internal/operators/maybe/MaybeMergeArray.java +++ b/src/main/java/io/reactivex/internal/operators/maybe/MaybeMergeArray.java @@ -201,7 +201,7 @@ void drainNormal() { Throwable ex = error.get(); if (ex != null) { q.clear(); - a.onError(error.terminate()); + error.tryTerminateConsumer(downstream); return; } @@ -227,7 +227,7 @@ void drainNormal() { Throwable ex = error.get(); if (ex != null) { q.clear(); - a.onError(error.terminate()); + error.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletable.java b/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletable.java index 249d01ef82..68ce47c9d1 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletable.java @@ -127,10 +127,7 @@ public void onError(Throwable t) { if (errors.addThrowable(t)) { if (errorMode == ErrorMode.IMMEDIATE) { inner.dispose(); - t = errors.terminate(); - if (t != ExceptionHelper.TERMINATED) { - downstream.onError(t); - } + errors.tryTerminateConsumer(downstream); if (getAndIncrement() == 0) { queue.clear(); } @@ -154,6 +151,7 @@ public void dispose() { disposed = true; upstream.cancel(); inner.dispose(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue.clear(); } @@ -168,10 +166,7 @@ void innerError(Throwable ex) { if (errors.addThrowable(ex)) { if (errorMode == ErrorMode.IMMEDIATE) { upstream.cancel(); - ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); if (getAndIncrement() == 0) { queue.clear(); } @@ -205,8 +200,7 @@ void drain() { if (errorMode == ErrorMode.BOUNDARY) { if (errors.get() != null) { queue.clear(); - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -216,12 +210,7 @@ void drain() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } @@ -245,8 +234,7 @@ void drain() { queue.clear(); upstream.cancel(); errors.addThrowable(ex); - ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } active = true; diff --git a/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybe.java b/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybe.java index 82a3009a6c..63018f0797 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybe.java @@ -167,6 +167,7 @@ public void cancel() { cancelled = true; upstream.cancel(); inner.dispose(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue.clear(); item = null; @@ -225,8 +226,7 @@ void drain() { || (errorMode == ErrorMode.BOUNDARY && s == STATE_INACTIVE)) { queue.clear(); item = null; - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -237,12 +237,7 @@ void drain() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); return; } @@ -267,8 +262,7 @@ void drain() { upstream.cancel(); queue.clear(); errors.addThrowable(ex); - ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingle.java b/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingle.java index 9be42fcb7b..1c76d2f808 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingle.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingle.java @@ -167,6 +167,7 @@ public void cancel() { cancelled = true; upstream.cancel(); inner.dispose(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue.clear(); item = null; @@ -220,8 +221,7 @@ void drain() { || (errorMode == ErrorMode.BOUNDARY && s == STATE_INACTIVE)) { queue.clear(); item = null; - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -232,12 +232,7 @@ void drain() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); return; } @@ -262,8 +257,7 @@ void drain() { upstream.cancel(); queue.clear(); errors.addThrowable(ex); - ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletable.java b/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletable.java index 1fae1bab6f..0979194f28 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletable.java @@ -128,10 +128,7 @@ public void onError(Throwable t) { onComplete(); } else { disposeInner(); - Throwable ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(t); @@ -142,12 +139,7 @@ public void onError(Throwable t) { public void onComplete() { done = true; if (inner.get() == null) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } } @@ -175,16 +167,12 @@ void innerError(SwitchMapInnerObserver sender, Throwable error) { if (errors.addThrowable(error)) { if (delayErrors) { if (done) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } else { upstream.cancel(); disposeInner(); - Throwable ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } return; } @@ -195,12 +183,7 @@ void innerError(SwitchMapInnerObserver sender, Throwable error) { void innerComplete(SwitchMapInnerObserver sender) { if (inner.compareAndSet(sender, null)) { if (done) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybe.java b/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybe.java index 9ea99b8d7e..0087a597d0 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybe.java @@ -221,8 +221,7 @@ void drain() { if (errors.get() != null) { if (!delayErrors) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -232,12 +231,7 @@ void drain() { boolean empty = current == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingle.java b/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingle.java index f176322fde..1d26e9964a 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingle.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingle.java @@ -215,8 +215,7 @@ void drain() { if (errors.get() != null) { if (!delayErrors) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -226,12 +225,7 @@ void drain() { boolean empty = current == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletable.java b/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletable.java index 41fa298128..900108866a 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletable.java @@ -140,10 +140,7 @@ public void onError(Throwable t) { if (errorMode == ErrorMode.IMMEDIATE) { disposed = true; inner.dispose(); - t = errors.terminate(); - if (t != ExceptionHelper.TERMINATED) { - downstream.onError(t); - } + errors.tryTerminateConsumer(downstream); if (getAndIncrement() == 0) { queue.clear(); } @@ -167,6 +164,7 @@ public void dispose() { disposed = true; upstream.dispose(); inner.dispose(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue.clear(); } @@ -182,10 +180,7 @@ void innerError(Throwable ex) { if (errorMode == ErrorMode.IMMEDIATE) { disposed = true; upstream.dispose(); - ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); if (getAndIncrement() == 0) { queue.clear(); } @@ -223,8 +218,7 @@ void drain() { if (errors.get() != null) { disposed = true; queue.clear(); - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -243,20 +237,17 @@ void drain() { disposed = true; queue.clear(); upstream.dispose(); - errors.addThrowable(ex); - ex = errors.terminate(); - downstream.onError(ex); + if (errors.addThrowable(ex)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(ex); + } return; } if (d && empty) { disposed = true; - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybe.java b/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybe.java index 32b174a19f..273b0cae9c 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybe.java @@ -145,6 +145,7 @@ public void dispose() { cancelled = true; upstream.dispose(); inner.dispose(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue.clear(); item = null; @@ -206,8 +207,7 @@ void drain() { || (errorMode == ErrorMode.BOUNDARY && s == STATE_INACTIVE)) { queue.clear(); item = null; - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -218,12 +218,7 @@ void drain() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); return; } @@ -240,8 +235,7 @@ void drain() { upstream.dispose(); queue.clear(); errors.addThrowable(ex); - ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingle.java b/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingle.java index 1358e1ed9c..9c3576154b 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingle.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingle.java @@ -145,6 +145,7 @@ public void dispose() { cancelled = true; upstream.dispose(); inner.dispose(); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue.clear(); item = null; @@ -201,8 +202,7 @@ void drain() { || (errorMode == ErrorMode.BOUNDARY && s == STATE_INACTIVE)) { queue.clear(); item = null; - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -213,12 +213,7 @@ void drain() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); return; } @@ -235,8 +230,7 @@ void drain() { upstream.dispose(); queue.clear(); errors.addThrowable(ex); - ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletable.java b/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletable.java index 84b3a82950..02c70482b9 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletable.java @@ -126,10 +126,7 @@ public void onError(Throwable t) { onComplete(); } else { disposeInner(); - Throwable ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } } else { RxJavaPlugins.onError(t); @@ -140,12 +137,7 @@ public void onError(Throwable t) { public void onComplete() { done = true; if (inner.get() == null) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } } @@ -173,16 +165,12 @@ void innerError(SwitchMapInnerObserver sender, Throwable error) { if (errors.addThrowable(error)) { if (delayErrors) { if (done) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } else { upstream.dispose(); disposeInner(); - Throwable ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } return; } @@ -193,12 +181,7 @@ void innerError(SwitchMapInnerObserver sender, Throwable error) { void innerComplete(SwitchMapInnerObserver sender) { if (inner.compareAndSet(sender, null)) { if (done) { - Throwable ex = errors.terminate(); - if (ex == null) { - downstream.onComplete(); - } else { - downstream.onError(ex); - } + errors.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybe.java b/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybe.java index 4bc76c15dc..f7d5c877ee 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybe.java @@ -211,8 +211,7 @@ void drain() { if (errors.get() != null) { if (!delayErrors) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -222,12 +221,7 @@ void drain() { boolean empty = current == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingle.java b/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingle.java index 8371d7773f..5fd19dc658 100644 --- a/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingle.java +++ b/src/main/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingle.java @@ -205,8 +205,7 @@ void drain() { if (errors.get() != null) { if (!delayErrors) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); return; } } @@ -216,12 +215,7 @@ void drain() { boolean empty = current == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMap.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMap.java index ce8d23acfd..56ba37365f 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMap.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMap.java @@ -165,7 +165,6 @@ public void dispose() { disposed = true; inner.dispose(); upstream.dispose(); - if (getAndIncrement() == 0) { queue.clear(); } @@ -280,7 +279,7 @@ static final class ConcatMapDelayErrorObserver final int bufferSize; - final AtomicThrowable error; + final AtomicThrowable errors; final DelayErrorInnerObserver observer; @@ -305,7 +304,7 @@ static final class ConcatMapDelayErrorObserver this.mapper = mapper; this.bufferSize = bufferSize; this.tillTheEnd = tillTheEnd; - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); this.observer = new DelayErrorInnerObserver(actual, this); } @@ -355,7 +354,7 @@ public void onNext(T value) { @Override public void onError(Throwable e) { - if (error.addThrowable(e)) { + if (errors.addThrowable(e)) { done = true; drain(); } else { @@ -379,6 +378,7 @@ public void dispose() { cancelled = true; upstream.dispose(); observer.dispose(); + errors.tryTerminateAndReport(); } @SuppressWarnings("unchecked") @@ -387,9 +387,9 @@ void drain() { return; } - Observer actual = this.downstream; + Observer downstream = this.downstream; SimpleQueue queue = this.queue; - AtomicThrowable error = this.error; + AtomicThrowable errors = this.errors; for (;;) { @@ -401,11 +401,11 @@ void drain() { } if (!tillTheEnd) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { queue.clear(); cancelled = true; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -420,8 +420,11 @@ void drain() { Exceptions.throwIfFatal(ex); cancelled = true; this.upstream.dispose(); - error.addThrowable(ex); - actual.onError(error.terminate()); + if (errors.addThrowable(ex)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(ex); + } return; } @@ -429,12 +432,7 @@ void drain() { if (d && empty) { cancelled = true; - Throwable ex = error.terminate(); - if (ex != null) { - actual.onError(ex); - } else { - actual.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } @@ -449,8 +447,11 @@ void drain() { cancelled = true; this.upstream.dispose(); queue.clear(); - error.addThrowable(ex); - actual.onError(error.terminate()); + if (errors.addThrowable(ex)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(ex); + } return; } @@ -461,12 +462,12 @@ void drain() { w = ((Supplier)o).get(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); - error.addThrowable(ex); + errors.addThrowable(ex); continue; } if (w != null && !cancelled) { - actual.onNext(w); + downstream.onNext(w); } continue; } else { @@ -508,7 +509,7 @@ public void onNext(R value) { @Override public void onError(Throwable e) { ConcatMapDelayErrorObserver p = parent; - if (p.error.addThrowable(e)) { + if (p.errors.addThrowable(e)) { if (!p.tillTheEnd) { p.upstream.dispose(); } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapEager.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapEager.java index 7028fdcf62..725d6895a7 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapEager.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapEager.java @@ -70,7 +70,7 @@ static final class ConcatMapEagerMainObserver final ErrorMode errorMode; - final AtomicThrowable error; + final AtomicThrowable errors; final ArrayDeque> observers; @@ -96,7 +96,7 @@ static final class ConcatMapEagerMainObserver this.maxConcurrency = maxConcurrency; this.prefetch = prefetch; this.errorMode = errorMode; - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); this.observers = new ArrayDeque>(); } @@ -146,7 +146,7 @@ public void onNext(T value) { @Override public void onError(Throwable e) { - if (error.addThrowable(e)) { + if (errors.addThrowable(e)) { done = true; drain(); } else { @@ -167,6 +167,7 @@ public void dispose() { } cancelled = true; upstream.dispose(); + errors.tryTerminateAndReport(); drainAndDispose(); } @@ -212,7 +213,7 @@ public void innerNext(InnerQueuedObserver inner, R value) { @Override public void innerError(InnerQueuedObserver inner, Throwable e) { - if (error.addThrowable(e)) { + if (errors.addThrowable(e)) { if (errorMode == ErrorMode.IMMEDIATE) { upstream.dispose(); } @@ -255,12 +256,12 @@ public void drain() { } if (errorMode == ErrorMode.IMMEDIATE) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { q.clear(); disposeAll(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -281,8 +282,11 @@ public void drain() { upstream.dispose(); q.clear(); disposeAll(); - error.addThrowable(ex); - a.onError(error.terminate()); + if (errors.addThrowable(ex)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(ex); + } return; } @@ -304,12 +308,12 @@ public void drain() { } if (errorMode == ErrorMode.IMMEDIATE) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { q.clear(); disposeAll(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); return; } } @@ -318,12 +322,12 @@ public void drain() { if (active == null) { if (errorMode == ErrorMode.BOUNDARY) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { q.clear(); disposeAll(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(a); return; } } @@ -334,12 +338,12 @@ public void drain() { boolean empty = active == null; if (d && empty) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { q.clear(); disposeAll(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(a); } else { a.onComplete(); } @@ -365,12 +369,12 @@ public void drain() { boolean d = active.isDone(); if (errorMode == ErrorMode.IMMEDIATE) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { q.clear(); disposeAll(); - a.onError(error.terminate()); + errors.tryTerminateConsumer(a); return; } } @@ -381,7 +385,7 @@ public void drain() { w = aq.poll(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); - error.addThrowable(ex); + errors.addThrowable(ex); current = null; activeCount--; diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapScheduler.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapScheduler.java index 6338521fda..5039371bb8 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapScheduler.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableConcatMapScheduler.java @@ -290,7 +290,7 @@ static final class ConcatMapDelayErrorObserver final int bufferSize; - final AtomicThrowable error; + final AtomicThrowable errors; final DelayErrorInnerObserver observer; @@ -317,7 +317,7 @@ static final class ConcatMapDelayErrorObserver this.mapper = mapper; this.bufferSize = bufferSize; this.tillTheEnd = tillTheEnd; - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); this.observer = new DelayErrorInnerObserver(actual, this); this.worker = worker; } @@ -368,7 +368,7 @@ public void onNext(T value) { @Override public void onError(Throwable e) { - if (error.addThrowable(e)) { + if (errors.addThrowable(e)) { done = true; drain(); } else { @@ -393,6 +393,7 @@ public void dispose() { upstream.dispose(); observer.dispose(); worker.dispose(); + errors.tryTerminateAndReport(); } void drain() { @@ -406,9 +407,9 @@ void drain() { @SuppressWarnings("unchecked") @Override public void run() { - Observer actual = this.downstream; + Observer downstream = this.downstream; SimpleQueue queue = this.queue; - AtomicThrowable error = this.error; + AtomicThrowable errors = this.errors; for (;;) { @@ -420,11 +421,11 @@ public void run() { } if (!tillTheEnd) { - Throwable ex = error.get(); + Throwable ex = errors.get(); if (ex != null) { queue.clear(); cancelled = true; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -440,8 +441,11 @@ public void run() { Exceptions.throwIfFatal(ex); cancelled = true; this.upstream.dispose(); - error.addThrowable(ex); - actual.onError(error.terminate()); + if (errors.addThrowable(ex)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(ex); + } worker.dispose(); return; } @@ -450,12 +454,7 @@ public void run() { if (d && empty) { cancelled = true; - Throwable ex = error.terminate(); - if (ex != null) { - actual.onError(ex); - } else { - actual.onComplete(); - } + errors.tryTerminateConsumer(downstream); worker.dispose(); return; } @@ -471,8 +470,11 @@ public void run() { cancelled = true; this.upstream.dispose(); queue.clear(); - error.addThrowable(ex); - actual.onError(error.terminate()); + if (errors.addThrowable(ex)) { + errors.tryTerminateConsumer(downstream); + } else { + RxJavaPlugins.onError(ex); + } worker.dispose(); return; } @@ -484,12 +486,12 @@ public void run() { w = ((Supplier)o).get(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); - error.addThrowable(ex); + errors.addThrowable(ex); continue; } if (w != null && !cancelled) { - actual.onNext(w); + downstream.onNext(w); } continue; } else { @@ -531,7 +533,7 @@ public void onNext(R value) { @Override public void onError(Throwable e) { ConcatMapDelayErrorObserver p = parent; - if (p.error.addThrowable(e)) { + if (p.errors.addThrowable(e)) { if (!p.tillTheEnd) { p.upstream.dispose(); } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMap.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMap.java index b920fa57a7..a3c9fb63cc 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMap.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMap.java @@ -361,14 +361,7 @@ void drainLoop() { } if (d && (svq == null || svq.isEmpty()) && n == 0 && nSources == 0) { - Throwable ex = errors.terminate(); - if (ex != ExceptionHelper.TERMINATED) { - if (ex == null) { - child.onComplete(); - } else { - child.onError(ex); - } - } + errors.tryTerminateConsumer(downstream); return; } @@ -487,10 +480,7 @@ boolean checkTerminate() { Throwable e = errors.get(); if (!delayErrors && (e != null)) { disposeAll(); - e = errors.terminate(); - if (e != ExceptionHelper.TERMINATED) { - downstream.onError(e); - } + errors.tryTerminateConsumer(downstream); return true; } return false; diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletable.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletable.java index 727d0bc2de..0f923106d7 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletable.java @@ -111,14 +111,14 @@ public void onError(Throwable e) { if (errors.addThrowable(e)) { if (delayErrors) { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } else { - dispose(); + disposed = true; + upstream.dispose(); + set.dispose(); if (getAndSet(0) > 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } } else { @@ -129,12 +129,7 @@ public void onError(Throwable e) { @Override public void onComplete() { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); } } @@ -143,6 +138,7 @@ public void dispose() { disposed = true; upstream.dispose(); set.dispose(); + errors.tryTerminateAndReport(); } @Override diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableCompletable.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableCompletable.java index 67691a11f8..b9a3040656 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableCompletable.java @@ -116,14 +116,14 @@ public void onError(Throwable e) { if (errors.addThrowable(e)) { if (delayErrors) { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } else { - dispose(); + disposed = true; + upstream.dispose(); + set.dispose(); if (getAndSet(0) > 0) { - Throwable ex = errors.terminate(); - downstream.onError(ex); + errors.tryTerminateConsumer(downstream); } } } else { @@ -134,12 +134,7 @@ public void onError(Throwable e) { @Override public void onComplete() { if (decrementAndGet() == 0) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); } } @@ -148,6 +143,7 @@ public void dispose() { disposed = true; upstream.dispose(); set.dispose(); + errors.tryTerminateAndReport(); } @Override diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybe.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybe.java index 122572ac50..ca655680c7 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybe.java @@ -138,6 +138,7 @@ public void dispose() { cancelled = true; upstream.dispose(); set.dispose(); + errors.tryTerminateAndReport(); } @Override @@ -154,12 +155,7 @@ void innerSuccess(InnerObserver inner, R value) { SpscLinkedArrayQueue q = queue.get(); if (d && (q == null || q.isEmpty())) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } if (decrementAndGet() == 0) { @@ -213,12 +209,7 @@ void innerComplete(InnerObserver inner) { SpscLinkedArrayQueue q = queue.get(); if (d && (q == null || q.isEmpty())) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } if (decrementAndGet() == 0) { @@ -260,9 +251,8 @@ void drainLoop() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - ex = errors.terminate(); clear(); - a.onError(ex); + errors.tryTerminateConsumer(a); return; } } @@ -273,12 +263,7 @@ void drainLoop() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingle.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingle.java index bedda3cb49..ef6648cea0 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingle.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingle.java @@ -138,6 +138,7 @@ public void dispose() { cancelled = true; upstream.dispose(); set.dispose(); + errors.tryTerminateAndReport(); } @Override @@ -154,12 +155,7 @@ void innerSuccess(InnerObserver inner, R value) { SpscLinkedArrayQueue q = queue.get(); if (d && (q == null || q.isEmpty())) { - Throwable ex = errors.terminate(); - if (ex != null) { - downstream.onError(ex); - } else { - downstream.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } if (decrementAndGet() == 0) { @@ -234,9 +230,8 @@ void drainLoop() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - ex = errors.terminate(); clear(); - a.onError(ex); + errors.tryTerminateConsumer(a); return; } } @@ -247,12 +242,7 @@ void drainLoop() { boolean empty = v == null; if (d && empty) { - Throwable ex = errors.terminate(); - if (ex != null) { - a.onError(ex); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(downstream); return; } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletable.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletable.java index 3b9e649062..444ac38189 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletable.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletable.java @@ -55,7 +55,7 @@ static final class MergeWithObserver extends AtomicInteger final OtherObserver otherObserver; - final AtomicThrowable error; + final AtomicThrowable errors; volatile boolean mainDone; @@ -65,7 +65,7 @@ static final class MergeWithObserver extends AtomicInteger this.downstream = downstream; this.mainDisposable = new AtomicReference(); this.otherObserver = new OtherObserver(this); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); } @Override @@ -75,20 +75,20 @@ public void onSubscribe(Disposable d) { @Override public void onNext(T t) { - HalfSerializer.onNext(downstream, t, this, error); + HalfSerializer.onNext(downstream, t, this, errors); } @Override public void onError(Throwable ex) { DisposableHelper.dispose(otherObserver); - HalfSerializer.onError(downstream, ex, this, error); + HalfSerializer.onError(downstream, ex, this, errors); } @Override public void onComplete() { mainDone = true; if (otherDone) { - HalfSerializer.onComplete(downstream, this, error); + HalfSerializer.onComplete(downstream, this, errors); } } @@ -101,17 +101,18 @@ public boolean isDisposed() { public void dispose() { DisposableHelper.dispose(mainDisposable); DisposableHelper.dispose(otherObserver); + errors.tryTerminateAndReport(); } void otherError(Throwable ex) { DisposableHelper.dispose(mainDisposable); - HalfSerializer.onError(downstream, ex, this, error); + HalfSerializer.onError(downstream, ex, this, errors); } void otherComplete() { otherDone = true; if (mainDone) { - HalfSerializer.onComplete(downstream, this, error); + HalfSerializer.onComplete(downstream, this, errors); } } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybe.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybe.java index e7caad3b21..3dac3fdae9 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybe.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybe.java @@ -58,7 +58,7 @@ static final class MergeWithObserver extends AtomicInteger final OtherObserver otherObserver; - final AtomicThrowable error; + final AtomicThrowable errors; volatile SimplePlainQueue queue; @@ -78,7 +78,7 @@ static final class MergeWithObserver extends AtomicInteger this.downstream = downstream; this.mainDisposable = new AtomicReference(); this.otherObserver = new OtherObserver(this); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); } @Override @@ -105,7 +105,7 @@ public void onNext(T t) { @Override public void onError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { DisposableHelper.dispose(otherObserver); drain(); } else { @@ -129,6 +129,7 @@ public void dispose() { disposed = true; DisposableHelper.dispose(mainDisposable); DisposableHelper.dispose(otherObserver); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue = null; singleItem = null; @@ -150,7 +151,7 @@ void otherSuccess(T value) { } void otherError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { DisposableHelper.dispose(mainDisposable); drain(); } else { @@ -190,10 +191,10 @@ void drainLoop() { return; } - if (error.get() != null) { + if (errors.get() != null) { singleItem = null; queue = null; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(actual); return; } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingle.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingle.java index 7332a29a25..7574eaf3ba 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingle.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingle.java @@ -58,7 +58,7 @@ static final class MergeWithObserver extends AtomicInteger final OtherObserver otherObserver; - final AtomicThrowable error; + final AtomicThrowable errors; volatile SimplePlainQueue queue; @@ -78,7 +78,7 @@ static final class MergeWithObserver extends AtomicInteger this.downstream = downstream; this.mainDisposable = new AtomicReference(); this.otherObserver = new OtherObserver(this); - this.error = new AtomicThrowable(); + this.errors = new AtomicThrowable(); } @Override @@ -105,7 +105,7 @@ public void onNext(T t) { @Override public void onError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { DisposableHelper.dispose(otherObserver); drain(); } else { @@ -129,6 +129,7 @@ public void dispose() { disposed = true; DisposableHelper.dispose(mainDisposable); DisposableHelper.dispose(otherObserver); + errors.tryTerminateAndReport(); if (getAndIncrement() == 0) { queue = null; singleItem = null; @@ -150,7 +151,7 @@ void otherSuccess(T value) { } void otherError(Throwable ex) { - if (error.addThrowable(ex)) { + if (errors.addThrowable(ex)) { DisposableHelper.dispose(mainDisposable); drain(); } else { @@ -185,10 +186,10 @@ void drainLoop() { return; } - if (error.get() != null) { + if (errors.get() != null) { singleItem = null; queue = null; - actual.onError(error.terminate()); + errors.tryTerminateConsumer(actual); return; } diff --git a/src/main/java/io/reactivex/internal/operators/observable/ObservableSwitchMap.java b/src/main/java/io/reactivex/internal/operators/observable/ObservableSwitchMap.java index 795e7cae50..fb4c762518 100644 --- a/src/main/java/io/reactivex/internal/operators/observable/ObservableSwitchMap.java +++ b/src/main/java/io/reactivex/internal/operators/observable/ObservableSwitchMap.java @@ -210,7 +210,7 @@ void drain() { } else { Throwable ex = errors.get(); if (ex != null) { - a.onError(errors.terminate()); + errors.tryTerminateConsumer(a); return; } if (empty) { @@ -236,7 +236,7 @@ void drain() { } else { Throwable ex = errors.get(); if (ex != null) { - a.onError(errors.terminate()); + errors.tryTerminateConsumer(a); return; } if (empty) { @@ -260,7 +260,7 @@ void drain() { if (!delayErrors) { Throwable ex = errors.get(); if (ex != null) { - a.onError(errors.terminate()); + errors.tryTerminateConsumer(a); return; } } diff --git a/src/main/java/io/reactivex/internal/operators/parallel/ParallelJoin.java b/src/main/java/io/reactivex/internal/operators/parallel/ParallelJoin.java index 975c151729..a5b8addd0b 100644 --- a/src/main/java/io/reactivex/internal/operators/parallel/ParallelJoin.java +++ b/src/main/java/io/reactivex/internal/operators/parallel/ParallelJoin.java @@ -428,12 +428,7 @@ void drainLoop() { } if (d && empty) { - Throwable ex = errors.get(); - if (ex != null) { - a.onError(errors.terminate()); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } @@ -463,12 +458,7 @@ void drainLoop() { } if (d && empty) { - Throwable ex = errors.get(); - if (ex != null) { - a.onError(errors.terminate()); - } else { - a.onComplete(); - } + errors.tryTerminateConsumer(a); return; } } diff --git a/src/main/java/io/reactivex/internal/util/AtomicThrowable.java b/src/main/java/io/reactivex/internal/util/AtomicThrowable.java index 6c7c06b54c..14aed2b98b 100644 --- a/src/main/java/io/reactivex/internal/util/AtomicThrowable.java +++ b/src/main/java/io/reactivex/internal/util/AtomicThrowable.java @@ -15,6 +15,9 @@ import java.util.concurrent.atomic.AtomicReference; +import org.reactivestreams.Subscriber; + +import io.reactivex.*; import io.reactivex.plugins.RxJavaPlugins; /** @@ -61,4 +64,82 @@ public void tryTerminateAndReport() { RxJavaPlugins.onError(ex); } } + + /** + * Tries to terminate this atomic throwable (by swapping in the TERMINATED indicator) + * and notifies the consumer if there was no error (onComplete) or there was a + * non-null, non-indicator exception contained before (onError). + * If there was a terminated indicator, the consumer is not signaled. + * @param consumer the consumer to notify + */ + public void tryTerminateConsumer(Subscriber consumer) { + Throwable ex = terminate(); + if (ex == null) { + consumer.onComplete(); + } else if (ex != ExceptionHelper.TERMINATED) { + consumer.onError(ex); + } + } + + /** + * Tries to terminate this atomic throwable (by swapping in the TERMINATED indicator) + * and notifies the consumer if there was no error (onComplete) or there was a + * non-null, non-indicator exception contained before (onError). + * If there was a terminated indicator, the consumer is not signaled. + * @param consumer the consumer to notify + */ + public void tryTerminateConsumer(Observer consumer) { + Throwable ex = terminate(); + if (ex == null) { + consumer.onComplete(); + } else if (ex != ExceptionHelper.TERMINATED) { + consumer.onError(ex); + } + } + + /** + * Tries to terminate this atomic throwable (by swapping in the TERMINATED indicator) + * and notifies the consumer if there was no error (onComplete) or there was a + * non-null, non-indicator exception contained before (onError). + * If there was a terminated indicator, the consumer is not signaled. + * @param consumer the consumer to notify + */ + public void tryTerminateConsumer(MaybeObserver consumer) { + Throwable ex = terminate(); + if (ex == null) { + consumer.onComplete(); + } else if (ex != ExceptionHelper.TERMINATED) { + consumer.onError(ex); + } + } + + /** + * Tries to terminate this atomic throwable (by swapping in the TERMINATED indicator) + * and notifies the consumer if there was no error (onComplete) or there was a + * non-null, non-indicator exception contained before (onError). + * If there was a terminated indicator, the consumer is not signaled. + * @param consumer the consumer to notify + */ + public void tryTerminateConsumer(SingleObserver consumer) { + Throwable ex = terminate(); + if (ex != null && ex != ExceptionHelper.TERMINATED) { + consumer.onError(ex); + } + } + + /** + * Tries to terminate this atomic throwable (by swapping in the TERMINATED indicator) + * and notifies the consumer if there was no error (onComplete) or there was a + * non-null, non-indicator exception contained before (onError). + * If there was a terminated indicator, the consumer is not signaled. + * @param consumer the consumer to notify + */ + public void tryTerminateConsumer(CompletableObserver consumer) { + Throwable ex = terminate(); + if (ex == null) { + consumer.onComplete(); + } else if (ex != ExceptionHelper.TERMINATED) { + consumer.onError(ex); + } + } } diff --git a/src/main/java/io/reactivex/internal/util/HalfSerializer.java b/src/main/java/io/reactivex/internal/util/HalfSerializer.java index 8e160ab2ea..067ee7fd2a 100644 --- a/src/main/java/io/reactivex/internal/util/HalfSerializer.java +++ b/src/main/java/io/reactivex/internal/util/HalfSerializer.java @@ -44,12 +44,7 @@ public static void onNext(Subscriber subscriber, T value, if (wip.get() == 0 && wip.compareAndSet(0, 1)) { subscriber.onNext(value); if (wip.decrementAndGet() != 0) { - Throwable ex = error.terminate(); - if (ex != null) { - subscriber.onError(ex); - } else { - subscriber.onComplete(); - } + error.tryTerminateConsumer(subscriber); } } } @@ -67,7 +62,7 @@ public static void onError(Subscriber subscriber, Throwable ex, AtomicInteger wip, AtomicThrowable error) { if (error.addThrowable(ex)) { if (wip.getAndIncrement() == 0) { - subscriber.onError(error.terminate()); + error.tryTerminateConsumer(subscriber); } } else { RxJavaPlugins.onError(ex); @@ -83,12 +78,7 @@ public static void onError(Subscriber subscriber, Throwable ex, */ public static void onComplete(Subscriber subscriber, AtomicInteger wip, AtomicThrowable error) { if (wip.getAndIncrement() == 0) { - Throwable ex = error.terminate(); - if (ex != null) { - subscriber.onError(ex); - } else { - subscriber.onComplete(); - } + error.tryTerminateConsumer(subscriber); } } @@ -106,12 +96,7 @@ public static void onNext(Observer observer, T value, if (wip.get() == 0 && wip.compareAndSet(0, 1)) { observer.onNext(value); if (wip.decrementAndGet() != 0) { - Throwable ex = error.terminate(); - if (ex != null) { - observer.onError(ex); - } else { - observer.onComplete(); - } + error.tryTerminateConsumer(observer); } } } @@ -129,7 +114,7 @@ public static void onError(Observer observer, Throwable ex, AtomicInteger wip, AtomicThrowable error) { if (error.addThrowable(ex)) { if (wip.getAndIncrement() == 0) { - observer.onError(error.terminate()); + error.tryTerminateConsumer(observer); } } else { RxJavaPlugins.onError(ex); @@ -145,12 +130,7 @@ public static void onError(Observer observer, Throwable ex, */ public static void onComplete(Observer observer, AtomicInteger wip, AtomicThrowable error) { if (wip.getAndIncrement() == 0) { - Throwable ex = error.terminate(); - if (ex != null) { - observer.onError(ex); - } else { - observer.onComplete(); - } + error.tryTerminateConsumer(observer); } } diff --git a/src/main/java/io/reactivex/observers/SerializedObserver.java b/src/main/java/io/reactivex/observers/SerializedObserver.java index 31badf77f8..703f024c03 100644 --- a/src/main/java/io/reactivex/observers/SerializedObserver.java +++ b/src/main/java/io/reactivex/observers/SerializedObserver.java @@ -74,6 +74,7 @@ public void onSubscribe(@NonNull Disposable d) { @Override public void dispose() { + done = true; upstream.dispose(); } diff --git a/src/test/java/io/reactivex/flowable/FlowableSubscriberTest.java b/src/test/java/io/reactivex/flowable/FlowableSubscriberTest.java index dd89d42e4d..dc4a5e1100 100644 --- a/src/test/java/io/reactivex/flowable/FlowableSubscriberTest.java +++ b/src/test/java/io/reactivex/flowable/FlowableSubscriberTest.java @@ -16,7 +16,6 @@ import static org.junit.Assert.*; import java.util.*; -import java.util.concurrent.*; import java.util.concurrent.atomic.*; import org.junit.*; diff --git a/src/test/java/io/reactivex/internal/operators/completable/CompletableMergeTest.java b/src/test/java/io/reactivex/internal/operators/completable/CompletableMergeTest.java index 54716b58ec..6639a92883 100644 --- a/src/test/java/io/reactivex/internal/operators/completable/CompletableMergeTest.java +++ b/src/test/java/io/reactivex/internal/operators/completable/CompletableMergeTest.java @@ -553,4 +553,44 @@ public void remove() { to.assertEmpty(); } + + @Test + public void arrayUndeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return Completable.mergeArray(upstream.ignoreElements(), Completable.complete().hide()); + } + }); + } + + @Test + public void iterableUndeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return Completable.merge(Arrays.asList(upstream.ignoreElements(), Completable.complete().hide())); + } + }); + } + + @Test + public void arrayUndeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return Completable.mergeArrayDelayError(upstream.ignoreElements(), Completable.complete().hide()); + } + }); + } + + @Test + public void iterableUndeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return Completable.mergeDelayError(Arrays.asList(upstream.ignoreElements(), Completable.complete().hide())); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableMostRecentTest.java b/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableMostRecentTest.java index 4a956f5efe..0bdf853813 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableMostRecentTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableMostRecentTest.java @@ -24,7 +24,6 @@ import io.reactivex.exceptions.TestException; import io.reactivex.processors.*; import io.reactivex.schedulers.TestScheduler; -import io.reactivex.testsupport.TestHelper; public class BlockingFlowableMostRecentTest extends RxJavaTest { @Test diff --git a/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableToFutureTest.java b/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableToFutureTest.java index 4608efa464..3ea818525f 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableToFutureTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/BlockingFlowableToFutureTest.java @@ -20,7 +20,6 @@ import java.util.*; import java.util.concurrent.*; -import io.reactivex.testsupport.TestHelper; import org.junit.*; import org.reactivestreams.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableAllTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableAllTest.java index 68f7ff697f..40f4cd191d 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableAllTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableAllTest.java @@ -28,7 +28,6 @@ import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; import io.reactivex.internal.subscriptions.BooleanSubscription; -import io.reactivex.observers.TestObserver; import io.reactivex.plugins.RxJavaPlugins; import io.reactivex.subscribers.TestSubscriber; import io.reactivex.testsupport.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableAmbTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableAmbTest.java index a5c59d11fa..655953cb1b 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableAmbTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableAmbTest.java @@ -17,7 +17,6 @@ import static org.mockito.Mockito.*; import java.io.IOException; -import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableAnyTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableAnyTest.java index cc82fc39e1..597eb600ef 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableAnyTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableAnyTest.java @@ -28,7 +28,6 @@ import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; import io.reactivex.internal.subscriptions.BooleanSubscription; -import io.reactivex.observers.TestObserver; import io.reactivex.plugins.RxJavaPlugins; import io.reactivex.subscribers.TestSubscriber; import io.reactivex.testsupport.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEagerTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEagerTest.java index 566fc430a9..225cb2b627 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapEagerTest.java @@ -15,16 +15,14 @@ import static org.junit.Assert.*; -import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; -import io.reactivex.RxJavaTest; import org.junit.*; import org.reactivestreams.*; -import io.reactivex.Flowable; +import io.reactivex.*; import io.reactivex.exceptions.*; import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; @@ -1327,4 +1325,49 @@ public void cancelNoInnerYet() { assertFalse(pp1.hasSubscribers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapEager(new Function>() { + @Override + public Flowable apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapEagerDelayError(new Function>() { + @Override + public Flowable apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, false); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapEagerDelayError(new Function>() { + @Override + public Flowable apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapSchedulerTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapSchedulerTest.java index 7c22acc479..4d7c735f1e 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapSchedulerTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapSchedulerTest.java @@ -1043,4 +1043,49 @@ public Flowable apply(Integer t) throws Throwable { assertTrue(ts.values().toString(), ts.values().get(0).startsWith("RxSingleScheduler-")); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMap(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, 2, ImmediateThinScheduler.INSTANCE); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, 2, false, ImmediateThinScheduler.INSTANCE); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, 2, true, ImmediateThinScheduler.INSTANCE); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapTest.java index 8112961042..6b572066cc 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableConcatMapTest.java @@ -207,4 +207,49 @@ public void delayErrorCallableEager() { .test() .assertFailure(NullPointerException.class, 1, 2, 3); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMap(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, 2, false); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, 2, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableDefaultIfEmptyTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableDefaultIfEmptyTest.java index 3b6a96bab5..5289d0bad0 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableDefaultIfEmptyTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableDefaultIfEmptyTest.java @@ -20,8 +20,6 @@ import org.reactivestreams.Subscriber; import io.reactivex.Flowable; -import io.reactivex.exceptions.TestException; -import io.reactivex.subscribers.DefaultSubscriber; import io.reactivex.testsupport.*; public class FlowableDefaultIfEmptyTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableTest.java index 73d6d7a2a9..06b1573e04 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapCompletableTest.java @@ -540,4 +540,34 @@ public void asyncMaxConcurrency() { } } } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.flatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.flatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybeTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybeTest.java index b06a3b8f8a..9f8e62f280 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapMaybeTest.java @@ -22,6 +22,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.*; +import io.reactivex.Flowable; import io.reactivex.disposables.*; import io.reactivex.exceptions.*; import io.reactivex.functions.Function; @@ -611,4 +612,34 @@ public void run() { TestHelper.race(r1, r2); } } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.flatMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.flatMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingleTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingleTest.java index cae060b5e7..71df815a56 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapSingleTest.java @@ -22,6 +22,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.*; +import io.reactivex.Flowable; import io.reactivex.disposables.*; import io.reactivex.exceptions.*; import io.reactivex.functions.Function; @@ -511,4 +512,34 @@ public MaybeSource apply(Integer v) throws Exception { .awaitDone(5, TimeUnit.SECONDS) .assertFailure(CompositeException.class); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.flatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.flatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapTest.java index 803a42925c..a4007a45a1 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableFlatMapTest.java @@ -20,11 +20,10 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.RxJavaTest; import org.junit.*; import org.reactivestreams.*; -import io.reactivex.Flowable; +import io.reactivex.*; import io.reactivex.exceptions.*; import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; @@ -1086,4 +1085,34 @@ public void accept(Integer v) throws Exception { assertFalse(pp3.hasSubscribers()); assertFalse(pp4.hasSubscribers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.flatMap(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.flatMap(new Function>() { + @Override + public Publisher apply(Integer v) throws Throwable { + return Flowable.just(v).hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeDelayErrorTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeDelayErrorTest.java index 29f21d6884..9d4ade5b3e 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeDelayErrorTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeDelayErrorTest.java @@ -16,13 +16,11 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.*; import io.reactivex.RxJavaTest; import org.junit.*; -import org.mockito.InOrder; import org.reactivestreams.*; import io.reactivex.Flowable; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeTest.java index ed6c7a5eb2..f7186243aa 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeTest.java @@ -17,7 +17,6 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletableTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletableTest.java index 932668e84f..9b1310f8b5 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithCompletableTest.java @@ -19,7 +19,7 @@ import io.reactivex.*; import io.reactivex.exceptions.TestException; -import io.reactivex.functions.Action; +import io.reactivex.functions.*; import io.reactivex.processors.PublishProcessor; import io.reactivex.subjects.CompletableSubject; import io.reactivex.subscribers.TestSubscriber; @@ -173,4 +173,14 @@ public void cancelMainOnOtherError() { assertFalse("main has observers!", pp.hasSubscribers()); assertFalse("other has observers", cs.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.mergeWith(Completable.complete().hide()); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybeTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybeTest.java index 793ef3cd0c..c4f8ec7370 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithMaybeTest.java @@ -438,4 +438,14 @@ public void cancelMainOnOtherError() { assertFalse("main has observers!", pp.hasSubscribers()); assertFalse("other has observers", ms.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.mergeWith(Maybe.just(1).hide()); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingleTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingleTest.java index 346ce655a0..5bbf30a363 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableMergeWithSingleTest.java @@ -434,4 +434,14 @@ public void cancelMainOnOtherError() { assertFalse("main has observers!", pp.hasSubscribers()); assertFalse("other has observers", ss.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.mergeWith(Single.just(1).hide()); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualTest.java index 08a5965c83..8bb2d5d105 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableSequenceEqualTest.java @@ -20,7 +20,7 @@ import org.junit.*; import org.mockito.InOrder; -import org.reactivestreams.Subscriber; +import org.reactivestreams.*; import io.reactivex.*; import io.reactivex.exceptions.*; @@ -550,4 +550,44 @@ protected void subscribeActual(Subscriber s) { RxJavaPlugins.reset(); } } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Single apply(Flowable upstream) { + return Flowable.sequenceEqual(Flowable.just(1).hide(), upstream); + } + }); + } + + @Test + public void undeliverableUponCancelAsFlowable() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return Flowable.sequenceEqual(Flowable.just(1).hide(), upstream).toFlowable(); + } + }); + } + + @Test + public void undeliverableUponCancel2() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Single apply(Flowable upstream) { + return Flowable.sequenceEqual(upstream, Flowable.just(1).hide()); + } + }); + } + + @Test + public void undeliverableUponCancelAsFlowable2() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return Flowable.sequenceEqual(upstream, Flowable.just(1).hide()).toFlowable(); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableSubscribeOnTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableSubscribeOnTest.java index eec9898d0b..e5aa6b4ed5 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableSubscribeOnTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableSubscribeOnTest.java @@ -32,7 +32,7 @@ import io.reactivex.subscribers.*; import io.reactivex.testsupport.*; -public class FlowableSubscribeOnTest extends RxJavaTest{ +public class FlowableSubscribeOnTest extends RxJavaTest { @Test public void issue813() throws InterruptedException { diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableTimeoutTests.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableTimeoutTests.java index b108188d04..1c400ac7b0 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableTimeoutTests.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableTimeoutTests.java @@ -17,7 +17,6 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import java.io.IOException; import java.util.List; import java.util.concurrent.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableToListTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableToListTest.java index 604177c90d..315ad3c3a6 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableToListTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableToListTest.java @@ -27,7 +27,6 @@ import io.reactivex.functions.*; import io.reactivex.observers.TestObserver; import io.reactivex.processors.PublishProcessor; -import io.reactivex.schedulers.Schedulers; import io.reactivex.subscribers.TestSubscriber; import io.reactivex.testsupport.*; diff --git a/src/test/java/io/reactivex/internal/operators/flowable/FlowableToSortedListTest.java b/src/test/java/io/reactivex/internal/operators/flowable/FlowableToSortedListTest.java index 7a93ce70a0..3c78899090 100644 --- a/src/test/java/io/reactivex/internal/operators/flowable/FlowableToSortedListTest.java +++ b/src/test/java/io/reactivex/internal/operators/flowable/FlowableToSortedListTest.java @@ -24,9 +24,6 @@ import org.reactivestreams.Subscriber; import io.reactivex.*; -import io.reactivex.observers.TestObserver; -import io.reactivex.processors.PublishProcessor; -import io.reactivex.schedulers.Schedulers; import io.reactivex.subscribers.TestSubscriber; import io.reactivex.testsupport.*; diff --git a/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletableTest.java b/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletableTest.java index f6f6e2c90e..50b2748ca7 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapCompletableTest.java @@ -386,4 +386,49 @@ public void doneButNotEmpty() { to.assertResult(); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.concatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.concatMapCompletableDelayError(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }, false, 2); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.concatMapCompletableDelayError(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybeTest.java b/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybeTest.java index 95237924f6..4e2500aae9 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapMaybeTest.java @@ -420,4 +420,48 @@ public void run() { } } + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapMaybeDelayError(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }, false, 2); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapMaybeDelayError(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingleTest.java b/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingleTest.java index f620204e9c..4e8c9e261d 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/FlowableConcatMapSingleTest.java @@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; -import org.reactivestreams.Subscriber; +import org.reactivestreams.*; import io.reactivex.*; import io.reactivex.disposables.Disposables; @@ -337,4 +337,49 @@ public void run() { ts.assertNoErrors(); } } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapSingleDelayError(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }, false, 2); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.concatMapSingleDelayError(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletableTest.java b/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletableTest.java index 3674119989..8c69d43b50 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapCompletableTest.java @@ -390,31 +390,31 @@ public void mainErrorDelayed() { @Test public void undeliverableUponCancel() { - List errors = TestHelper.trackPluginErrors(); - try { - final TestObserverEx to = new TestObserverEx(); - - Flowable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Throwable { - to.dispose(); - throw new TestException(); - } - }) - .switchMapCompletable(new Function() { - @Override - public Completable apply(Integer v) throws Throwable { - return Completable.complete().hide(); - } - }) - .subscribe(to); - - to.assertEmpty(); + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.switchMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); + } - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter() { + @Override + public Completable apply(Flowable upstream) { + return upstream.switchMapCompletableDelayError(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybeTest.java b/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybeTest.java index ce6456b23e..782c7016ce 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapMaybeTest.java @@ -649,31 +649,31 @@ public void onNext(Integer t) { @Test public void undeliverableUponCancel() { - List errors = TestHelper.trackPluginErrors(); - try { - final TestSubscriberEx ts = new TestSubscriberEx(); - - Flowable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Throwable { - ts.cancel(); - throw new TestException(); - } - }) - .switchMapMaybe(new Function>() { - @Override - public Maybe apply(Integer v) throws Throwable { - return Maybe.just(v).hide(); - } - }) - .subscribe(ts); - - ts.assertEmpty(); + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.switchMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); + } - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.switchMapMaybeDelayError(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingleTest.java b/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingleTest.java index 44ca692f87..707009fda1 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/FlowableSwitchMapSingleTest.java @@ -606,31 +606,31 @@ public void backpressured() { @Test public void undeliverableUponCancel() { - List errors = TestHelper.trackPluginErrors(); - try { - final TestSubscriberEx ts = new TestSubscriberEx(); - - Flowable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Throwable { - ts.cancel(); - throw new TestException(); - } - }) - .switchMapSingle(new Function>() { - @Override - public Single apply(Integer v) throws Throwable { - return Single.just(v).hide(); - } - }) - .subscribe(ts); - - ts.assertEmpty(); + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.switchMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); + } - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new FlowableConverter>() { + @Override + public Flowable apply(Flowable upstream) { + return upstream.switchMapSingleDelayError(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletableTest.java b/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletableTest.java index 8cd6d652c9..3cbafe04a3 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapCompletableTest.java @@ -429,4 +429,49 @@ public void justScalarSource() { to.assertResult(); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.concatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.concatMapCompletableDelayError(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }, false, 2); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.concatMapCompletableDelayError(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybeTest.java b/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybeTest.java index 2aa377413a..bc485f6963 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapMaybeTest.java @@ -441,4 +441,49 @@ public void run() { to.assertNoErrors(); } } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapMaybeDelayError(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }, false, 2); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapMaybeDelayError(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingleTest.java b/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingleTest.java index b89c846057..03424521ea 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/ObservableConcatMapSingleTest.java @@ -382,4 +382,48 @@ public void run() { } } + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapSingleDelayError(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }, false, 2); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapSingleDelayError(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }, true, 2); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletableTest.java b/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletableTest.java index 830f93c6d4..47f0c7cb31 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletableTest.java @@ -27,7 +27,7 @@ import io.reactivex.observers.TestObserver; import io.reactivex.plugins.RxJavaPlugins; import io.reactivex.subjects.*; -import io.reactivex.testsupport.*; +import io.reactivex.testsupport.TestHelper; public class ObservableSwitchMapCompletableTest extends RxJavaTest { @@ -432,31 +432,31 @@ public void scalarSource() { @Test public void undeliverableUponCancel() { - List errors = TestHelper.trackPluginErrors(); - try { - final TestObserverEx to = new TestObserverEx(); - - Observable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Throwable { - to.dispose(); - throw new TestException(); - } - }) - .switchMapCompletable(new Function() { - @Override - public Completable apply(Integer v) throws Throwable { - return Completable.complete().hide(); - } - }) - .subscribe(to); - - to.assertEmpty(); + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.switchMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); + } - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.switchMapCompletableDelayError(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybeTest.java b/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybeTest.java index 809123bad8..cd68f3dfb2 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapMaybeTest.java @@ -689,31 +689,31 @@ public void scalarSource() { @Test public void undeliverableUponCancel() { - List errors = TestHelper.trackPluginErrors(); - try { - final TestObserverEx to = new TestObserverEx(); - - Observable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Throwable { - to.dispose(); - throw new TestException(); - } - }) - .switchMapMaybe(new Function>() { - @Override - public Maybe apply(Integer v) throws Throwable { - return Maybe.just(v).hide(); - } - }) - .subscribe(to); - - to.assertEmpty(); + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.switchMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); + } - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.switchMapMaybeDelayError(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); } } diff --git a/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingleTest.java b/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingleTest.java index 761872045b..aab021dd8c 100644 --- a/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/mixed/ObservableSwitchMapSingleTest.java @@ -657,31 +657,31 @@ public void scalarSource() { @Test public void undeliverableUponCancel() { - List errors = TestHelper.trackPluginErrors(); - try { - final TestObserverEx to = new TestObserverEx(); - - Observable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Throwable { - to.dispose(); - throw new TestException(); - } - }) - .switchMapSingle(new Function>() { - @Override - public Single apply(Integer v) throws Throwable { - return Single.just(v).hide(); - } - }) - .subscribe(to); - - to.assertEmpty(); + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.switchMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); + } - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.switchMapSingleDelayError(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapEagerTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapEagerTest.java index 98e3ba9029..cd646dcd21 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapEagerTest.java @@ -20,11 +20,10 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.*; -import io.reactivex.RxJavaTest; import org.junit.*; +import io.reactivex.*; import io.reactivex.Observable; -import io.reactivex.ObservableSource; import io.reactivex.exceptions.*; import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; @@ -1006,4 +1005,49 @@ public void cancelNoInnerYet() { assertFalse(ps1.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapEager(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapEagerDelayError(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, false); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapEagerDelayError(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapSchedulerTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapSchedulerTest.java index b6d1b8b0fa..baa84610f5 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapSchedulerTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapSchedulerTest.java @@ -1004,4 +1004,49 @@ public Observable apply(Integer t) throws Throwable { assertTrue(to.values().toString(), to.values().get(0).startsWith("RxSingleScheduler-")); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMap(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, 2, ImmediateThinScheduler.INSTANCE); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, 2, false, ImmediateThinScheduler.INSTANCE); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, 2, true, ImmediateThinScheduler.INSTANCE); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapTest.java index fd6d7738da..6836e3743c 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableConcatMapTest.java @@ -522,4 +522,49 @@ public void run() throws Exception { assertEquals(0, counter.get()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMap(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, 2, false); + } + }); + } + + @Test + public void undeliverableUponCancelDelayErrorTillEnd() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.concatMapDelayError(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, 2, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableDefaultIfEmptyTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableDefaultIfEmptyTest.java index c9311901c1..d37579b68c 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableDefaultIfEmptyTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableDefaultIfEmptyTest.java @@ -18,8 +18,6 @@ import org.junit.*; import io.reactivex.*; -import io.reactivex.exceptions.TestException; -import io.reactivex.observers.DefaultObserver; import io.reactivex.testsupport.TestHelper; public class ObservableDefaultIfEmptyTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableTest.java index f351af3b28..010201262e 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapCompletableTest.java @@ -476,4 +476,34 @@ public CompletableSource apply(Integer v) throws Exception { } }, false, 1, null); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.flatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter() { + @Override + public Completable apply(Observable upstream) { + return upstream.flatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Throwable { + return Completable.complete().hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybeTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybeTest.java index 0aedbbfee0..b1a25797e1 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapMaybeTest.java @@ -455,4 +455,34 @@ protected void subscribeActual(MaybeObserver observer) { to .assertEmpty(); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.flatMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.flatMapMaybe(new Function>() { + @Override + public Maybe apply(Integer v) throws Throwable { + return Maybe.just(v).hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingleTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingleTest.java index 160a33ec1d..3851bf9edc 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapSingleTest.java @@ -370,4 +370,34 @@ protected void subscribeActual(SingleObserver observer) { to .assertEmpty(); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.flatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.flatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Throwable { + return Single.just(v).hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapTest.java index be5ef458bb..6830f8af49 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableFlatMapTest.java @@ -14,17 +14,17 @@ package io.reactivex.internal.operators.observable; import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.RxJavaTest; import org.junit.*; +import io.reactivex.*; import io.reactivex.Observable; -import io.reactivex.ObservableSource; import io.reactivex.Observer; import io.reactivex.disposables.*; import io.reactivex.exceptions.*; @@ -1047,4 +1047,34 @@ public void accept(Integer v) throws Exception { assertFalse(ps3.hasObservers()); assertFalse(ps4.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.flatMap(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }); + } + }); + } + + @Test + public void undeliverableUponCancelDelayError() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.flatMap(new Function>() { + @Override + public Observable apply(Integer v) throws Throwable { + return Observable.just(v).hide(); + } + }, true); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeDelayErrorTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeDelayErrorTest.java index 436cbd3c4f..af874adc39 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeDelayErrorTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeDelayErrorTest.java @@ -21,7 +21,6 @@ import io.reactivex.RxJavaTest; import org.junit.*; -import org.mockito.InOrder; import io.reactivex.Observable; import io.reactivex.ObservableSource; diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletableTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletableTest.java index 31ab72f78e..c54a13d28d 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletableTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithCompletableTest.java @@ -172,4 +172,14 @@ public void cancelMainOnOtherError() { assertFalse("main has observers!", ps.hasObservers()); assertFalse("other has observers", cs.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.mergeWith(Completable.complete().hide()); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybeTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybeTest.java index d7e27be02f..0d7c3e0b3b 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybeTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithMaybeTest.java @@ -308,4 +308,14 @@ public void cancelMainOnOtherError() { assertFalse("main has observers!", ps.hasObservers()); assertFalse("other has observers", ms.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.mergeWith(Maybe.just(1).hide()); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingleTest.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingleTest.java index 8c896bd118..fa13cb2133 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingleTest.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableMergeWithSingleTest.java @@ -300,4 +300,14 @@ public void cancelMainOnOtherError() { assertFalse("main has observers!", ps.hasObservers()); assertFalse("other has observers", ss.hasObservers()); } + + @Test + public void undeliverableUponCancel() { + TestHelper.checkUndeliverableUponCancel(new ObservableConverter>() { + @Override + public Observable apply(Observable upstream) { + return upstream.mergeWith(Single.just(1).hide()); + } + }); + } } diff --git a/src/test/java/io/reactivex/internal/operators/observable/ObservableTimeoutTests.java b/src/test/java/io/reactivex/internal/operators/observable/ObservableTimeoutTests.java index 499e92726f..effe1031e8 100644 --- a/src/test/java/io/reactivex/internal/operators/observable/ObservableTimeoutTests.java +++ b/src/test/java/io/reactivex/internal/operators/observable/ObservableTimeoutTests.java @@ -17,7 +17,6 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import java.io.IOException; import java.util.List; import java.util.concurrent.*; diff --git a/src/test/java/io/reactivex/internal/util/AtomicThrowableTest.java b/src/test/java/io/reactivex/internal/util/AtomicThrowableTest.java index 6c0e674aeb..9c2024f4e7 100644 --- a/src/test/java/io/reactivex/internal/util/AtomicThrowableTest.java +++ b/src/test/java/io/reactivex/internal/util/AtomicThrowableTest.java @@ -17,11 +17,15 @@ import java.util.List; -import io.reactivex.RxJavaTest; import org.junit.Test; +import io.reactivex.*; +import io.reactivex.disposables.Disposables; import io.reactivex.exceptions.TestException; +import io.reactivex.internal.subscriptions.BooleanSubscription; +import io.reactivex.observers.TestObserver; import io.reactivex.plugins.RxJavaPlugins; +import io.reactivex.subscribers.TestSubscriber; import io.reactivex.testsupport.TestHelper; public class AtomicThrowableTest extends RxJavaTest { @@ -84,4 +88,164 @@ public void tryTerminateAndReportHasError() { RxJavaPlugins.reset(); } } + + @Test + public void tryTerminateConsumerSubscriberNoError() { + TestSubscriber ts = new TestSubscriber(); + ts.onSubscribe(new BooleanSubscription()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.tryTerminateConsumer(ts); + ts.assertResult(); + } + + @Test + public void tryTerminateConsumerSubscriberError() { + TestSubscriber ts = new TestSubscriber(); + ts.onSubscribe(new BooleanSubscription()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.set(new TestException()); + ex.tryTerminateConsumer(ts); + ts.assertFailure(TestException.class); + } + + @Test + public void tryTerminateConsumerSubscriberTerminated() { + TestSubscriber ts = new TestSubscriber(); + ts.onSubscribe(new BooleanSubscription()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.terminate(); + ex.tryTerminateConsumer(ts); + ts.assertEmpty(); + } + + @Test + public void tryTerminateConsumerObserverNoError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.tryTerminateConsumer((Observer)to); + to.assertResult(); + } + + @Test + public void tryTerminateConsumerObserverError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.set(new TestException()); + ex.tryTerminateConsumer((Observer)to); + to.assertFailure(TestException.class); + } + + @Test + public void tryTerminateConsumerObserverTerminated() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.terminate(); + ex.tryTerminateConsumer((Observer)to); + to.assertEmpty(); + } + + @Test + public void tryTerminateConsumerMaybeObserverNoError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.tryTerminateConsumer((MaybeObserver)to); + to.assertResult(); + } + + @Test + public void tryTerminateConsumerMaybeObserverError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.set(new TestException()); + ex.tryTerminateConsumer((MaybeObserver)to); + to.assertFailure(TestException.class); + } + + @Test + public void tryTerminateConsumerMaybeObserverTerminated() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.terminate(); + ex.tryTerminateConsumer((MaybeObserver)to); + to.assertEmpty(); + } + + @Test + public void tryTerminateConsumerSingleNoError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.tryTerminateConsumer((SingleObserver)to); + to.assertEmpty(); + } + + @Test + public void tryTerminateConsumerSingleError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.set(new TestException()); + ex.tryTerminateConsumer((SingleObserver)to); + to.assertFailure(TestException.class); + } + + @Test + public void tryTerminateConsumerSingleTerminated() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.terminate(); + ex.tryTerminateConsumer((SingleObserver)to); + to.assertEmpty(); + } + + @Test + public void tryTerminateConsumerCompletableObserverNoError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.tryTerminateConsumer((CompletableObserver)to); + to.assertResult(); + } + + @Test + public void tryTerminateConsumerCompletableObserverError() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.set(new TestException()); + ex.tryTerminateConsumer((CompletableObserver)to); + to.assertFailure(TestException.class); + } + + @Test + public void tryTerminateConsumerCompletableObserverTerminated() { + TestObserver to = new TestObserver(); + to.onSubscribe(Disposables.empty()); + + AtomicThrowable ex = new AtomicThrowable(); + ex.terminate(); + ex.tryTerminateConsumer((CompletableObserver)to); + to.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/testsupport/TestHelper.java b/src/test/java/io/reactivex/testsupport/TestHelper.java index f649c725c0..838db6bcf2 100644 --- a/src/test/java/io/reactivex/testsupport/TestHelper.java +++ b/src/test/java/io/reactivex/testsupport/TestHelper.java @@ -3255,4 +3255,140 @@ public static File findSource(String baseClassName) throws Exception { return f; } + + /** + * Cancels a flow before notifying a transformation and checks if an undeliverable exception + * has been signaled due to the cancellation. + * @param transform the operator to test + * @param the output type of the transformation + */ + public static void checkUndeliverableUponCancel(FlowableConverter transform) { + List errors = TestHelper.trackPluginErrors(); + try { + + final SerialDisposable disposable = new SerialDisposable(); + + T result = Flowable.just(1) + .map(new Function() { + @Override + public Integer apply(Integer v) throws Throwable { + disposable.dispose(); + throw new TestException(); + } + }) + .to(transform); + + if (result instanceof MaybeSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((MaybeSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof SingleSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((SingleSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof CompletableSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((CompletableSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof ObservableSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((ObservableSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof Publisher) { + TestSubscriberEx ts = new TestSubscriberEx(); + disposable.set(Disposables.fromSubscription(ts)); + + ((Publisher)result) + .subscribe(ts); + ts.assertEmpty(); + } else { + fail("Unsupported transformation output: " + result + " of class " + (result != null ? result.getClass() : " ")); + } + + assertFalse("No undeliverable errors received", errors.isEmpty()); + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + /** + * Cancels a flow before notifying a transformation and checks if an undeliverable exception + * has been signaled due to the cancellation. + * @param transform the operator to test + * @param the output type of the transformation + */ + public static void checkUndeliverableUponCancel(ObservableConverter transform) { + List errors = TestHelper.trackPluginErrors(); + try { + + final SerialDisposable disposable = new SerialDisposable(); + + T result = Observable.just(1) + .map(new Function() { + @Override + public Integer apply(Integer v) throws Throwable { + disposable.dispose(); + throw new TestException(); + } + }) + .to(transform); + + if (result instanceof MaybeSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((MaybeSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof SingleSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((SingleSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof CompletableSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((CompletableSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof ObservableSource) { + TestObserverEx to = new TestObserverEx(); + disposable.set(to); + + ((ObservableSource)result) + .subscribe(to); + to.assertEmpty(); + } else if (result instanceof Publisher) { + TestSubscriberEx ts = new TestSubscriberEx(); + disposable.set(Disposables.fromSubscription(ts)); + + ((Publisher)result) + .subscribe(ts); + ts.assertEmpty(); + } else { + fail("Unsupported transformation output: " + result + " of class " + (result != null ? result.getClass() : " ")); + } + + assertFalse("No undeliverable errors received", errors.isEmpty()); + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } }