use of org.reactivestreams.Subscriber in project RxJava by ReactiveX.
the class BlockingFlowableLatestTest method onError.
@SuppressWarnings("unchecked")
@Test
public void onError() {
Iterator<Object> it = Flowable.never().blockingLatest().iterator();
List<Throwable> errors = TestHelper.trackPluginErrors();
try {
((Subscriber<Object>) it).onError(new TestException());
TestHelper.assertUndeliverable(errors, 0, TestException.class);
} finally {
RxJavaPlugins.reset();
}
}
use of org.reactivestreams.Subscriber in project reactive-streams-jvm by reactive-streams.
the class PublisherVerification method required_spec109_mustIssueOnSubscribeForNonNullSubscriber.
@Override
@Test
public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
activePublisherTest(0, false, new PublisherTestRun<T>() {
@Override
public void run(Publisher<T> pub) throws Throwable {
final Latch onSubscribeLatch = new Latch(env);
final AtomicReference<Subscription> cancel = new AtomicReference<Subscription>();
try {
pub.subscribe(new Subscriber<T>() {
@Override
public void onError(Throwable cause) {
onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
}
@Override
public void onSubscribe(Subscription subs) {
cancel.set(subs);
onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
onSubscribeLatch.close();
}
@Override
public void onNext(T elem) {
onSubscribeLatch.assertClosed("onSubscribe should be called prior to onNext always");
}
@Override
public void onComplete() {
onSubscribeLatch.assertClosed("onSubscribe should be called prior to onComplete always");
}
});
onSubscribeLatch.expectClose("Should have received onSubscribe");
env.verifyNoAsyncErrorsNoDelay();
} finally {
Subscription s = cancel.getAndSet(null);
if (s != null) {
s.cancel();
}
}
}
});
}
use of org.reactivestreams.Subscriber in project reactive-streams-jvm by reactive-streams.
the class PublisherVerificationTest method demandIgnoringAsynchronousPublisherVerification.
/**
* Verification using a Publisher that publishes elements even with no demand available, from multiple threads (!).
*/
final PublisherVerification<Integer> demandIgnoringAsynchronousPublisherVerification(final ExecutorService signallersPool, final boolean swallowOnNextExceptions) {
final AtomicInteger startedSignallingThreads = new AtomicInteger(0);
final int maxSignallingThreads = 2;
final AtomicBoolean concurrentAccessCaused = new AtomicBoolean(false);
return new PublisherVerification<Integer>(newTestEnvironment()) {
@Override
public Publisher<Integer> createPublisher(long elements) {
return new Publisher<Integer>() {
@Override
public void subscribe(final Subscriber<? super Integer> s) {
s.onSubscribe(new NoopSubscription() {
@Override
public void request(final long n) {
Runnable signalling = new Runnable() {
@Override
public void run() {
for (long i = 0; i <= n; i++) {
try {
final long signal = i;
signallersPool.execute(new Runnable() {
@Override
public void run() {
try {
s.onNext((int) signal);
} catch (Exception ex) {
if (!swallowOnNextExceptions) {
throw new RuntimeException("onNext threw an exception!", ex);
} else {
// yes, swallow the exception, we're not asserting and they'd just end up being logged (stdout),
// which we do not need in this specific PublisherVerificationTest
}
}
}
});
} catch (Exception ex) {
if (ex instanceof TestEnvironment.Latch.ExpectedOpenLatchException) {
if (concurrentAccessCaused.compareAndSet(false, true)) {
throw new RuntimeException("Concurrent access detected", ex);
} else {
// error signalled once already, stop more errors from propagating
return;
}
} else if (ex instanceof RejectedExecutionException) {
// ignore - this may happen since one thread may have already gotten into a concurrent access
// problem and initiated the pool's shutdown. It will then throw RejectedExecutionException.
} else {
if (concurrentAccessCaused.get()) {
return;
} else {
throw new RuntimeException(ex);
}
}
}
}
}
};
// must be guarded like this in case a Subscriber triggers request() synchronously from it's onNext()
while (startedSignallingThreads.getAndAdd(1) < maxSignallingThreads) {
signallersPool.execute(signalling);
}
}
});
}
};
}
@Override
public Publisher<Integer> createFailedPublisher() {
return SKIP;
}
};
}
use of org.reactivestreams.Subscriber in project reactive-streams-jvm by reactive-streams.
the class PublisherVerificationTest method required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue_forSynchronousPublisher.
@Test
public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue_forSynchronousPublisher() throws Throwable {
final AtomicInteger sent = new AtomicInteger();
customPublisherVerification(new Publisher<Integer>() {
@Override
public void subscribe(final Subscriber<? super Integer> downstream) {
downstream.onSubscribe(new Subscription() {
boolean started;
boolean cancelled;
@Override
public void request(long n) {
if (!started) {
started = true;
while (!cancelled) {
downstream.onNext(sent.getAndIncrement());
}
}
}
@Override
public void cancel() {
cancelled = true;
}
});
}
}).required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue();
// 11 due to the implementation of this particular TCK test (see impl)
Assert.assertEquals(sent.get(), 11);
}
use of org.reactivestreams.Subscriber in project reactive-streams-jvm by reactive-streams.
the class PublisherVerificationTest method stochastic_spec103_mustSignalOnMethodsSequentially_shouldFailBy_concurrentlyAccessingOnNext.
@Test
public void stochastic_spec103_mustSignalOnMethodsSequentially_shouldFailBy_concurrentlyAccessingOnNext() throws Throwable {
final AtomicInteger startedSignallingThreads = new AtomicInteger(0);
// this is an arbitrary number, we just need "many threads" to try to force an concurrent access scenario
final int maxSignallingThreads = 10;
final ExecutorService signallersPool = Executors.newFixedThreadPool(maxSignallingThreads);
final AtomicBoolean concurrentAccessCaused = new AtomicBoolean(false);
// highly specialised threadpool driven publisher which aims to FORCE concurrent access,
// so that we can confirm the test is able to catch this.
final Publisher<Integer> concurrentAccessPublisher = new Publisher<Integer>() {
@Override
public void subscribe(final Subscriber<? super Integer> s) {
s.onSubscribe(new NoopSubscription() {
@Override
public void request(final long n) {
Runnable signalling = new Runnable() {
@Override
public void run() {
for (long i = 0; i < n; i++) {
try {
// shutdown cleanly in when the threadpool is shutting down
if (Thread.interrupted()) {
return;
}
s.onNext((int) i);
} catch (Exception ex) {
// signal others to shut down
signallersPool.shutdownNow();
if (ex instanceof TestEnvironment.Latch.ExpectedOpenLatchException) {
if (!concurrentAccessCaused.getAndSet(true)) {
throw new RuntimeException("Concurrent access detected", ex);
} else {
// error signalled once already, stop more errors from propagating
return;
}
} else {
throw new RuntimeException(ex);
}
}
}
}
};
// must be guarded like this in case a Subscriber triggers request() synchronously from it's onNext()
while (startedSignallingThreads.getAndAdd(1) < maxSignallingThreads && !signallersPool.isShutdown()) {
try {
signallersPool.execute(signalling);
} catch (RejectedExecutionException ex) {
// ignore, should be safe as it means the pool is shutting down -> which means we triggered the problem we wanted to
return;
}
}
}
});
}
};
try {
requireTestFailure(new ThrowingRunnable() {
@Override
public void run() throws Throwable {
customPublisherVerification(concurrentAccessPublisher).stochastic_spec103_mustSignalOnMethodsSequentially();
}
}, "Illegal concurrent access detected");
} finally {
signallersPool.shutdownNow();
signallersPool.awaitTermination(1, TimeUnit.SECONDS);
}
}
Aggregations