@Test public void forkJoinPoolWorkQueueRejectsSubscribers() { ExecutorService executorService = Executors.newWorkStealingPool(2); WorkQueueProcessor<String> bc = WorkQueueProcessor.<String>builder().executor(executorService).bufferSize(16).build(); CountDownLatch latch = new CountDownLatch(2); TestWorkQueueSubscriber spec1 = new TestWorkQueueSubscriber(latch, "spec1"); TestWorkQueueSubscriber spec2 = new TestWorkQueueSubscriber(latch, "spec2"); TestWorkQueueSubscriber spec3 = new TestWorkQueueSubscriber(latch, "spec3"); bc.subscribe(spec1); bc.subscribe(spec2); bc.subscribe(spec3); bc.onNext("foo"); bc.onComplete(); assertThat(spec1.error, is(nullValue())); assertThat(spec2.error, is(nullValue())); assertThat(spec3.error, is(notNullValue())); assertThat(spec3.error.getMessage(), is("The executor service could not accommodate another subscriber, detected limit 2")); try { latch.await(1, TimeUnit.SECONDS); } catch (InterruptedException e1) { fail(e1.toString()); } }
@Test public void fixedThreadPoolWorkQueueRejectsSubscribers() { ExecutorService executorService = Executors.newFixedThreadPool(2); WorkQueueProcessor<String> bc = WorkQueueProcessor.<String>builder().executor(executorService).bufferSize(16).build(); CountDownLatch latch = new CountDownLatch(3); TestWorkQueueSubscriber spec1 = new TestWorkQueueSubscriber(latch, "spec1"); TestWorkQueueSubscriber spec2 = new TestWorkQueueSubscriber(latch, "spec2"); TestWorkQueueSubscriber spec3 = new TestWorkQueueSubscriber(latch, "spec3"); bc.subscribe(spec1); bc.subscribe(spec2); bc.subscribe(spec3); bc.onNext("foo"); bc.onComplete(); assertThat(spec1.error, is(nullValue())); assertThat(spec2.error, is(nullValue())); assertThat(spec3.error, is(notNullValue())); assertThat(spec3.error.getMessage(), startsWith( "The executor service could not accommodate another subscriber, detected limit 2")); try { latch.await(1, TimeUnit.SECONDS); } catch (InterruptedException e1) { fail(e1.toString()); } }
@Test(timeout = 15000L) public void completeDoesNotHang() throws Exception { WorkQueueProcessor<String> wq = WorkQueueProcessor.create(); wq.subscribe(); Assert.assertTrue(wq.downstreamCount() == 1); wq.onComplete(); while (wq.downstreamCount() != 0 && Thread.activeCount() > 2) { } }
@Test public void retryErrorPropagatedFromWorkQueueSubscriberCold() throws Exception { AtomicInteger errors = new AtomicInteger(3); WorkQueueProcessor<Integer> wq = WorkQueueProcessor.<Integer>builder().autoCancel(false).build(); AtomicInteger onNextSignals = new AtomicInteger(); wq.onNext(1); wq.onNext(2); wq.onNext(3); wq.onComplete(); StepVerifier.create(wq.log("wq", Level.FINE) .doOnNext(e -> onNextSignals.incrementAndGet()).<Integer>handle( (s1, sink) -> { if (errors.decrementAndGet() > 0) { sink.error(new RuntimeException()); } else { sink.next(s1); } }).retry()) .expectNext(1, 2, 3) .verifyComplete(); assertThat(onNextSignals.get(), equalTo(5)); while (wq.downstreamCount() != 0 && Thread.activeCount() > 1) { } }
@Test() public void retryNoThreadLeak() throws Exception { WorkQueueProcessor<Integer> wq = WorkQueueProcessor.<Integer>builder().autoCancel(false).build(); wq.handle((integer, sink) -> sink.error(new RuntimeException())) .retry(10) .subscribe(); wq.onNext(1); wq.onNext(2); wq.onNext(3); wq.onComplete(); while (wq.downstreamCount() != 0 && Thread.activeCount() > 1) { } }
.verify(); wq.onComplete();
.verify(); wq.onComplete();
@Override public void stop() { processor.onComplete(); }