/**
* Copyright (c) 2016-present, RxJava Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations under the License.
*/
package io.reactivex.processors;
import io.reactivex.Observable;
import io.reactivex.TestHelper;
import io.reactivex.disposables.Disposable;
import io.reactivex.exceptions.TestException;
import io.reactivex.internal.fuseable.QueueSubscription;
import io.reactivex.internal.subscriptions.BooleanSubscription;
import io.reactivex.plugins.RxJavaPlugins;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subscribers.SubscriberFusion;
import io.reactivex.subscribers.TestSubscriber;
import org.junit.Test;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.*;
public class UnicastProcessorTest extends DelayedFlowableProcessorTest<Object> {
@Override
protected FlowableProcessor<Object> create() {
return UnicastProcessor.create();
}
@Test
public void fusionLive() {
UnicastProcessor<Integer> ap = UnicastProcessor.create();
TestSubscriber<Integer> ts = SubscriberFusion.newTest(QueueSubscription.ANY);
ap.subscribe(ts);
ts
.assertOf(SubscriberFusion.<Integer>assertFuseable())
.assertOf(SubscriberFusion.<Integer>assertFusionMode(QueueSubscription.ASYNC));
ts.assertNoValues().assertNoErrors().assertNotComplete();
ap.onNext(1);
ts.assertValue(1).assertNoErrors().assertNotComplete();
ap.onComplete();
ts.assertResult(1);
}
@Test
public void fusionOfflie() {
UnicastProcessor<Integer> ap = UnicastProcessor.create();
ap.onNext(1);
ap.onComplete();
TestSubscriber<Integer> ts = SubscriberFusion.newTest(QueueSubscription.ANY);
ap.subscribe(ts);
ts
.assertOf(SubscriberFusion.<Integer>assertFuseable())
.assertOf(SubscriberFusion.<Integer>assertFusionMode(QueueSubscription.ASYNC))
.assertResult(1);
}
@Test
public void failFast() {
UnicastProcessor<Integer> ap = UnicastProcessor.create(false);
ap.onNext(1);
ap.onError(new RuntimeException());
TestSubscriber<Integer> ts = TestSubscriber.create();
ap.subscribe(ts);
ts
.assertValueCount(0)
.assertError(RuntimeException.class);
}
@Test
public void failFastFusionOffline() {
UnicastProcessor<Integer> ap = UnicastProcessor.create(false);
ap.onNext(1);
ap.onError(new RuntimeException());
TestSubscriber<Integer> ts = SubscriberFusion.newTest(QueueSubscription.ANY);
ap.subscribe(ts);
ts
.assertValueCount(0)
.assertError(RuntimeException.class);
}
@Test
public void threeArgsFactory() {
Runnable noop = new Runnable() {
@Override
public void run() {
}
};
UnicastProcessor<Integer> ap = UnicastProcessor.create(16, noop,false);
ap.onNext(1);
ap.onError(new RuntimeException());
TestSubscriber<Integer> ts = TestSubscriber.create();
ap.subscribe(ts);
ts
.assertValueCount(0)
.assertError(RuntimeException.class);
}
@Test
public void onTerminateCalledWhenOnError() {
final AtomicBoolean didRunOnTerminate = new AtomicBoolean();
UnicastProcessor<Integer> us = UnicastProcessor.create(Observable.bufferSize(), new Runnable() {
@Override public void run() {
didRunOnTerminate.set(true);
}
});
assertEquals(false, didRunOnTerminate.get());
us.onError(new RuntimeException("some error"));
assertEquals(true, didRunOnTerminate.get());
}
@Test
public void onTerminateCalledWhenOnComplete() {
final AtomicBoolean didRunOnTerminate = new AtomicBoolean();
UnicastProcessor<Integer> us = UnicastProcessor.create(Observable.bufferSize(), new Runnable() {
@Override public void run() {
didRunOnTerminate.set(true);
}
});
assertEquals(false, didRunOnTerminate.get());
us.onComplete();
assertEquals(true, didRunOnTerminate.get());
}
@Test
public void onTerminateCalledWhenCanceled() {
final AtomicBoolean didRunOnTerminate = new AtomicBoolean();
UnicastProcessor<Integer> us = UnicastProcessor.create(Observable.bufferSize(), new Runnable() {
@Override public void run() {
didRunOnTerminate.set(true);
}
});
final Disposable subscribe = us.subscribe();
assertEquals(false, didRunOnTerminate.get());
subscribe.dispose();
assertEquals(true, didRunOnTerminate.get());
}
@Test(expected = NullPointerException.class)
public void nullOnTerminate() {
UnicastProcessor.create(5, null);
}
@Test(expected = IllegalArgumentException.class)
public void negativeCapacityHint() {
UnicastProcessor.create(-1);
}
@Test(expected = IllegalArgumentException.class)
public void zeroCapacityHint() {
UnicastProcessor.create(0);
}
@Test
public void completeCancelRace() {
for (int i = 0; i < 500; i++) {
final int[] calls = { 0 };
final UnicastProcessor<Object> up = UnicastProcessor.create(100, new Runnable() {
@Override
public void run() {
calls[0]++;
}
});
final TestSubscriber<Object> ts = up.test();
Runnable r1 = new Runnable() {
@Override
public void run() {
ts.cancel();
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
up.onComplete();
}
};
TestHelper.race(r1, r2, Schedulers.single());
assertEquals(1, calls[0]);
}
}
@Test
public void afterDone() {
UnicastProcessor<Object> p = UnicastProcessor.create();
p.onComplete();
BooleanSubscription bs = new BooleanSubscription();
p.onSubscribe(bs);
p.onNext(1);
List<Throwable> errors = TestHelper.trackPluginErrors();
try {
p.onError(new TestException());
TestHelper.assertUndeliverable(errors, 0, TestException.class);
} finally {
RxJavaPlugins.reset();
}
p.onComplete();
p.test().assertResult();
assertNull(p.getThrowable());
assertTrue(p.hasComplete());
assertFalse(p.hasThrowable());
}
@Test
public void onErrorStatePeeking() {
UnicastProcessor<Object> p = UnicastProcessor.create();
assertFalse(p.hasComplete());
assertFalse(p.hasThrowable());
assertNull(p.getThrowable());
TestException ex = new TestException();
p.onError(ex);
assertFalse(p.hasComplete());
assertTrue(p.hasThrowable());
assertSame(ex, p.getThrowable());
}
@Test
public void rejectSyncFusion() {
UnicastProcessor<Object> p = UnicastProcessor.create();
TestSubscriber<Object> ts = SubscriberFusion.newTest(QueueSubscription.SYNC);
p.subscribe(ts);
SubscriberFusion.assertFusion(ts, QueueSubscription.NONE);
}
@Test
public void cancelOnArrival() {
UnicastProcessor.create()
.test(0L, true)
.assertEmpty();
}
@Test
public void multiSubscriber() {
UnicastProcessor<Object> p = UnicastProcessor.create();
TestSubscriber<Object> ts = p.test();
p.test()
.assertFailure(IllegalStateException.class);
p.onNext(1);
p.onComplete();
ts.assertResult(1);
}
@Test
public void fusedDrainCancel() {
for (int i = 0; i < 500; i++) {
final UnicastProcessor<Object> p = UnicastProcessor.create();
final TestSubscriber<Object> ts = SubscriberFusion.newTest(QueueSubscription.ANY);
p.subscribe(ts);
Runnable r1 = new Runnable() {
@Override
public void run() {
p.onNext(1);
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
ts.cancel();
}
};
TestHelper.race(r1, r2, Schedulers.single());
}
}
}