@Test public void testCustomRequestTaskThreadNameShare() { String expectedName = "workQueueProcessorRequestTaskShare"; //NOTE: the below single executor should not be used usually as requestTask assumes it immediately gets executed ExecutorService customTaskExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, expectedName)); WorkQueueProcessor<Object> processor = WorkQueueProcessor.builder() .executor(Executors.newCachedThreadPool()) .requestTaskExecutor(customTaskExecutor) .bufferSize(8) .waitStrategy(WaitStrategy.liteBlocking()) .autoCancel(true) .build(); processor.requestTask(Operators.cancelledSubscription()); processor.subscribe(); Thread[] threads = new Thread[Thread.activeCount()]; Thread.enumerate(threads); //cleanup to avoid visibility in other tests customTaskExecutor.shutdownNow(); processor.forceShutdown(); Condition<Thread> customRequestTaskThread = new Condition<>( thread -> thread != null && expectedName.equals(thread.getName()), "a thread named \"%s\"", expectedName); Assertions.assertThat(threads) .haveExactly(1, customRequestTaskThread); }
@Test(timeout = 5_000) public void testBufferSize1Created() throws Exception { WorkQueueProcessor<String> broadcast = WorkQueueProcessor.<String>builder() .share(true).name("share-name") .bufferSize(1) .autoCancel(true) .build(); int simultaneousSubscribers = 3000; CountDownLatch latch = new CountDownLatch(simultaneousSubscribers); Scheduler scheduler = Schedulers.single(); FluxSink<String> sink = broadcast.sink(); Flux<String> flux = broadcast.filter(Objects::nonNull) .publishOn(scheduler) .cache(1); for (int i = 0; i < simultaneousSubscribers; i++) { flux.subscribe(s -> latch.countDown()); } sink.next("data"); Assertions.assertThat(latch.await(4, TimeUnit.SECONDS)) .overridingErrorMessage("Data not received") .isTrue(); }
@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(timeout = 5_000) public void testBufferSize1Shared() throws Exception { WorkQueueProcessor<String> broadcast = WorkQueueProcessor.<String>builder() .share(true) .name("share-name") .bufferSize(1) .autoCancel(true) .build(); int simultaneousSubscribers = 3000; CountDownLatch latch = new CountDownLatch(simultaneousSubscribers); Scheduler scheduler = Schedulers.single(); FluxSink<String> sink = broadcast.sink(); Flux<String> flux = broadcast.filter(Objects::nonNull) .publishOn(scheduler) .cache(1); for (int i = 0; i < simultaneousSubscribers; i++) { flux.subscribe(s -> latch.countDown()); } sink.next("data"); Assertions.assertThat(latch.await(4, TimeUnit.SECONDS)) .overridingErrorMessage("Data not received") .isTrue(); }
@Test public void shareOverrideAll() { ExecutorService executor = Executors.newSingleThreadExecutor(); ExecutorService requestTaskExecutor = Executors.newSingleThreadExecutor(); int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .executor(executor) .requestTaskExecutor(requestTaskExecutor) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, null, bufferSize, waitStrategy, autoCancel, executor, requestTaskExecutor); }
@Test public void createOverrideAll() { ExecutorService executor = Executors.newSingleThreadExecutor(); ExecutorService requestTaskExecutor = Executors.newSingleThreadExecutor(); int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .executor(executor) .requestTaskExecutor(requestTaskExecutor) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, null, bufferSize, waitStrategy, autoCancel, executor, requestTaskExecutor); }
@Test public void shareDefaultExecutorOverrideAll() { String name = "nameOverride"; int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .name(name) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, name, bufferSize, waitStrategy, autoCancel, null, null); }
@Test public void createOverrideExecutorBufferSizeWaitStrategyAutoCancel() { ExecutorService executor = Executors.newSingleThreadExecutor(); int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .executor(executor) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, null, bufferSize, waitStrategy, autoCancel, executor, null); }
@Test public void createDefaultExecutorOverrideAll() { String name = "nameOverride"; int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .name(name) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, name, bufferSize, waitStrategy, autoCancel, null, null); }
@Test public void shareOverrideExecutorBufferSizeWaitStrategyAutoCancel() { ExecutorService executor = Executors.newSingleThreadExecutor(); int bufferSize = 1024; WaitStrategy waitStrategy = WaitStrategy.busySpin(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .executor(executor) .bufferSize(bufferSize) .waitStrategy(waitStrategy) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, null, bufferSize, waitStrategy, autoCancel, executor, null); }
@Test public void shareOverrideExecutorBufferSizeAutoCancel() { ExecutorService executor = Executors.newSingleThreadExecutor(); int bufferSize = 1024; boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .executor(executor) .bufferSize(bufferSize) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, null, bufferSize, null, autoCancel, executor, null); }
@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) { } }
@Test public void shareOverrideAutoCancel() { boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, null, null, null, autoCancel, null, null); }
@Test public void createOverrideExecutorBufferSizeAutoCancel() { ExecutorService executor = Executors.newSingleThreadExecutor(); int bufferSize = 1024; boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .executor(executor) .bufferSize(bufferSize) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, null, bufferSize, null, autoCancel, executor, null); }
@Test public void createOverrideExecutorAutoCancel() { ExecutorService executor = Executors.newSingleThreadExecutor(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .executor(executor) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, null, null, null, autoCancel, executor, null); }
@Test(timeout = 15000L) public void disposeSubscribeNoThreadLeak() throws Exception { WorkQueueProcessor<String> wq = WorkQueueProcessor.<String>builder().autoCancel(false).build(); Disposable d = wq.subscribe(); d.dispose(); d = wq.subscribe(); d.dispose(); d = wq.subscribe(); d.dispose(); while (wq.downstreamCount() != 0 && Thread.activeCount() > 2) { } }
private void setupPipeline() { processor = TopicProcessor.<String>builder().autoCancel(false).build(); workProcessor = WorkQueueProcessor.<String>builder().autoCancel(false).build(); processor.subscribe(workProcessor); }
@Test public void shareOverrideExecutorAutoCancel() { ExecutorService executor = Executors.newSingleThreadExecutor(); boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .share(true) .executor(executor) .autoCancel(autoCancel) .build(); assertProcessor(processor, true, null, null, null, autoCancel, executor, null); }
@Test public void createOverrideAutoCancel() { boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .autoCancel(autoCancel) .build(); assertProcessor(processor, false, null, null, null, autoCancel, null, null); }
@Test public void createOverrideNameBufferSizeAutoCancel() { String name = "nameOverride"; int bufferSize = 1024; boolean autoCancel = false; WorkQueueProcessor<Integer> processor = WorkQueueProcessor.<Integer>builder() .name(name) .bufferSize(bufferSize) .autoCancel(autoCancel) .build(); assertProcessor(processor, false, name, bufferSize, null, autoCancel, null, null); }