@Test public void writeText() throws Exception { EmitterProcessor<String> processor = EmitterProcessor.create(); ResponseBodyEmitter emitter = handleValue(processor, Flux.class, forClass(String.class)); EmitterHandler emitterHandler = new EmitterHandler(); emitter.initialize(emitterHandler); processor.onNext("The quick"); processor.onNext(" brown fox jumps over "); processor.onNext("the lazy dog"); processor.onComplete(); assertEquals("The quick brown fox jumps over the lazy dog", emitterHandler.getValuesAsText()); }
@Override public <U> UpdateHandlerRegistration<U> registerUpdateHandler( SubscriptionQueryMessage<?, ?, ?> query, SubscriptionQueryBackpressure backpressure, int updateBufferSize) { EmitterProcessor<SubscriptionQueryUpdateMessage<U>> processor = EmitterProcessor.create(updateBufferSize); FluxSink<SubscriptionQueryUpdateMessage<U>> sink = processor.sink(backpressure.getOverflowStrategy()); sink.onDispose(() -> updateHandlers.remove(query)); FluxSinkWrapper<SubscriptionQueryUpdateMessage<U>> fluxSinkWrapper = new FluxSinkWrapper<>(sink); updateHandlers.put(query, fluxSinkWrapper); Registration registration = () -> { fluxSinkWrapper.complete(); return true; }; return new UpdateHandlerRegistration<>(registration, processor.replay(updateBufferSize).autoConnect()); }
@Test public void scanMainCancelled() { EmitterProcessor test = EmitterProcessor.create(); test.onSubscribe(Operators.cancelledSubscription()); assertThat(test.scan(CANCELLED)).isTrue(); assertThat(test.isCancelled()).isTrue(); }
@Override @Nullable public Object scanUnsafe(Attr key) { if (key == Attr.PARENT) return s; if (key == Attr.BUFFERED) return getPending(); if (key == Attr.CANCELLED) return isCancelled(); if (key == Attr.PREFETCH) return getPrefetch(); return super.scanUnsafe(key); }
/** * Create a new {@link EmitterProcessor} using {@link Queues#SMALL_BUFFER_SIZE} * backlog size and auto-cancel. * * @param <E> Type of processed signals * * @return a fresh processor */ public static <E> EmitterProcessor<E> create() { return create(Queues.SMALL_BUFFER_SIZE, true); }
@Test public void state(){ EmitterProcessor<Integer> tp = EmitterProcessor.create(); assertThat(tp.getPending()).isEqualTo(0); assertThat(tp.getBufferSize()).isEqualTo(Queues.SMALL_BUFFER_SIZE); assertThat(tp.isCancelled()).isFalse(); assertThat(tp.inners()).isEmpty(); Disposable d1 = tp.subscribe(); assertThat(tp.inners()).hasSize(1); FluxSink<Integer> s = tp.sink(); assertThat(tp.getPending()).isEqualTo(0); AtomicReference<Subscription> d2 = new AtomicReference<>(); tp.subscribe(new CoreSubscriber<Integer>() { @Override public void onSubscribe(Subscription s) { s.next(6); s.next(7); assertThat(tp.scan(BUFFERED)).isEqualTo(3); assertThat(tp.isTerminated()).isFalse(); s.complete(); assertThat(tp.isTerminated()).isFalse(); d1.dispose(); d2.get().cancel(); assertThat(tp.isTerminated()).isTrue();
@Test public void shouldCorrectlyDispatchBatchedTimeout() throws InterruptedException { long timeout = 100; final int batchsize = 4; int parallelStreams = 16; CountDownLatch latch = new CountDownLatch(1); final EmitterProcessor<Integer> streamBatcher = EmitterProcessor.create(); streamBatcher.publishOn(asyncGroup) .bufferTimeout(batchsize, Duration.ofSeconds(timeout)) .log("batched") .parallel(parallelStreams) .groups() .log("batched-inner") .subscribe(innerStream -> innerStream.publishOn(asyncGroup) .doOnError(Throwable::printStackTrace) .subscribe(i -> latch.countDown())); streamBatcher.onNext(12); streamBatcher.onNext(123); streamBatcher.onNext(42); streamBatcher.onNext(666); boolean finished = latch.await(2, TimeUnit.SECONDS); if (!finished) { throw new RuntimeException(latch.getCount()+""); } else { assertEquals("Must have correct latch number : " + latch.getCount(), latch.getCount(), 0); } }
@Test public void normalAtomicRingBufferBackpressured() { EmitterProcessor<Integer> tp = EmitterProcessor.create(100); StepVerifier.create(tp, 0L) .then(() -> { Assert.assertTrue("No subscribers?", tp.hasDownstreams()); Assert.assertFalse("Completed?", tp.isTerminated()); Assert.assertNull("Has error?", tp.getError()); }) .then(() -> { tp.onNext(1); tp.onNext(2); tp.onComplete(); }) .thenRequest(10L) .expectNext(1, 2) .expectComplete() .verify(); Assert.assertFalse("Subscribers present?", tp.hasDownstreams()); Assert.assertTrue("Not completed?", tp.isTerminated()); Assert.assertNull("Has error?", tp.getError()); }
@Test public void simpleReactiveSubscriber() throws InterruptedException { EmitterProcessor<String> str = EmitterProcessor.create(); str.publishOn(asyncGroup) .subscribe(new FooSubscriber()); str.onNext("Goodbye World!"); str.onNext("Goodbye World!"); str.onComplete(); Thread.sleep(500); }
@Test public void whenReducingKnownNumberOfValuesOnlyFinalValueIsPassedToConsumers() { // "When reducing a known number of values, only the final value is passed to consumers" // given: "a composable with a known number of values and a reduce function" EmitterProcessor<Integer> source = EmitterProcessor.create(); Mono<Integer> reduced = source.reduce(new Reduction()); List<Integer> values = new ArrayList<>(); reduced.doOnSuccess(values::add).subscribe(); // when: "the expected number of values is accepted" source.onNext(1); source.onNext(2); source.onNext(3); source.onNext(4); source.onNext(5); source.onComplete(); // then: "the consumer only receives the final value" assertThat(values).containsExactly(120); }
@Test public void fluxValuesCanBeMapped() { // "A Flux"s values can be mapped" // given: "a source composable with a mapping function" EmitterProcessor<Integer> source = EmitterProcessor.create(); Flux<Integer> mapped = source.map(it -> it * 2); // when: "the source accepts a value" AtomicReference<Integer> value = new AtomicReference<>(); mapped.subscribe(value::set); source.onNext(1); // then: "the value is mapped" assertThat(value.get()).isEqualTo(2); }
@Test public void disconnect() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); EmitterProcessor<Integer> e = EmitterProcessor.create(); ConnectableFlux<Integer> p = e.publish(); p.subscribe(ts); Disposable r = p.connect(); e.onNext(1); e.onNext(2); r.dispose(); ts.assertValues(1, 2) .assertError(CancellationException.class) .assertNotComplete(); Assert.assertFalse("sp has subscribers?", e.downstreamCount() != 0); }
/** * Tests that Producer send Exceptions do not cancel Record Publishers when stopOnError=false */ @Test public void sendDontStopOnSerializationError() throws Exception { ProducerRecord<Integer, String> recordToFail = createProducerRecord(0, false); ProducerRecord<Integer, String> recordToSucceed = createProducerRecord(1, true); recreateSender(senderOptions.stopOnError(false).producerProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, FirstTimeFailingStringSerializer.class.getName())); Semaphore errorSemaphore = new Semaphore(0); EmitterProcessor<ProducerRecord<Integer, String>> processor = EmitterProcessor.create(); kafkaSender.send(processor.map(producerRecord -> SenderRecord.create(producerRecord, null))) .doOnError(t -> errorSemaphore.release()) .subscribe(); FluxSink<ProducerRecord<Integer, String>> sink = processor.sink(); sink.next(recordToFail); sink.next(recordToSucceed); sink.complete(); waitForMessages(consumer, 1, true); assertTrue("Error callback not invoked", errorSemaphore.tryAcquire(requestTimeoutMillis, TimeUnit.MILLISECONDS)); }
@Test public void streamAndPoolExplicitCompression() { EmitterProcessor<String> ep = EmitterProcessor.create(); .then(res.compression(true) .options(op -> op.flushOnEach()) .sendString(ep.log()).then()))) .wiretap(true) .bindNow(); .then(() -> ep.onNext("test1")) .expectNext("test1") .thenAwait(Duration.ofMillis(30)) .then(() -> ep.onNext("test2")) .thenAwait(Duration.ofMillis(30)) .expectNext("test2") .thenAwait(Duration.ofMillis(30)) .then(() -> ep.onComplete()) .verifyComplete();
@Test public void singleSubscriberOnly() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); AtomicInteger emission = new AtomicInteger(); Flux<Integer> source = Flux.range(1, 2).doOnNext(v -> emission.getAndIncrement()); EmitterProcessor<Integer> source1 = EmitterProcessor.create(); EmitterProcessor<Integer> source2 = EmitterProcessor.create(); source.flatMap(v -> v == 1 ? source1 : source2, 1, 32).subscribe(ts); Assert.assertEquals(1, emission.get()); ts.assertNoValues() .assertNoError() .assertNotComplete(); Assert.assertTrue("source1 no subscribers?", source1.downstreamCount() != 0); Assert.assertFalse("source2 has subscribers?", source2.downstreamCount() != 0); source1.onNext(1); source2.onNext(10); source1.onComplete(); source2.onNext(2); source2.onComplete(); ts.assertValues(1, 10, 2) .assertNoError() .assertComplete(); }
CountDownLatch latch = new CountDownLatch(elements); Processor<Integer, Integer> processor = EmitterProcessor.create(1024); EmitterProcessor<Integer> stream = EmitterProcessor.create(); FluxSink<Integer> session = stream.sink(); stream.subscribe(processor); latch.getCount() == 0); stream.onComplete();