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);
}
}
use of org.reactivestreams.Subscriber in project reactive-streams-jvm by reactive-streams.
the class PublisherVerificationTest method multiSubscribersPublisherVerification.
/**
* Verification using a Publisher that supports multiple subscribers
* @param shouldBlowUp if true {@link RuntimeException} will be thrown during second subscription.
*/
final PublisherVerification<Integer> multiSubscribersPublisherVerification(final boolean shouldBlowUp) {
return new PublisherVerification<Integer>(newTestEnvironment()) {
@Override
public Publisher<Integer> createPublisher(final long elements) {
return new Publisher<Integer>() {
private final Collection<CancelableSubscription> subscriptions = new CopyOnWriteArrayList<CancelableSubscription>();
private final AtomicLong source = new AtomicLong(elements);
@Override
public void subscribe(Subscriber<? super Integer> s) {
// onSubscribe first
CancelableSubscription subscription = new CancelableSubscription(s);
s.onSubscribe(subscription);
if (shouldBlowUp && !subscriptions.isEmpty()) {
s.onError(new RuntimeException("Unexpected additional subscriber"));
} else {
subscriptions.add(subscription);
}
}
class CancelableSubscription implements Subscription {
final AtomicBoolean canceled = new AtomicBoolean();
Subscriber<? super Integer> subscriber;
CancelableSubscription(Subscriber<? super Integer> subscriber) {
this.subscriber = subscriber;
}
@Override
public void request(long n) {
if (!canceled.get()) {
for (long i = 0; i < n; i++) {
if (source.getAndDecrement() < 0) {
canceled.set(true);
subscriber.onComplete();
} else {
subscriber.onNext((int) i);
}
}
}
}
@Override
public void cancel() {
canceled.set(true);
subscriber = null;
subscriptions.remove(this);
}
}
};
}
@Override
public Publisher<Integer> createFailedPublisher() {
return SKIP;
}
};
}
use of org.reactivestreams.Subscriber in project cyclops by aol.
the class IterableFlatMapTest method flatMapAsyncRS.
@Test
public void flatMapAsyncRS() {
for (int k = 0; k < 1000; k++) {
complete = new AtomicBoolean(false);
count = new AtomicInteger(0);
ReactiveSubscriber<Integer> sub = Spouts.reactiveSubscriber();
Spouts.of(1, 2, 3).peek(System.out::println).concatMap(i -> nextAsyncRS()).subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
subs = s;
}
@Override
public void onNext(Integer integer) {
System.out.println("RECIEVED " + integer);
assertThat(integer, Matchers.isOneOf(1, 2));
System.out.println("count " + count.incrementAndGet());
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
complete.set(true);
}
});
subs.request(Long.MAX_VALUE);
while (!complete.get()) {
}
assertThat(count.get(), equalTo(6));
}
}
Aggregations