@Test public void shouldPropagateErrorCorrectly() { Flux<String> switchTransformed = Flux.error(new RuntimeException("hello")) .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); StepVerifier.create(switchTransformed) .expectErrorMessage("hello") .verify(Duration.ofSeconds(10)); }
@Test public void shouldPropagateonCompleteCorrectly() { Flux<String> switchTransformed = Flux.empty() .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); StepVerifier.create(switchTransformed).expectComplete().verify(Duration.ofSeconds(10)); }
.doOnCancel(latch::countDown) .transform( flux -> new SwitchTransformFlux<>(flux, (first, innerFlux) -> innerFlux));
@Test public void shouldRequestExpectedAmountOfElements() throws InterruptedException { TestPublisher<Long> publisher = TestPublisher.createCold(); AtomicLong capture = new AtomicLong(); AtomicLong requested = new AtomicLong(); CountDownLatch latch = new CountDownLatch(1); Flux<Long> switchTransformed = publisher .flux() .doOnRequest(requested::addAndGet) .transform(flux -> new SwitchTransformFlux<>(flux, (first, innerFlux) -> innerFlux)); publisher.next(1L); switchTransformed.subscribe( capture::set, __ -> {}, latch::countDown, s -> { for (int i = 0; i < 10000; i++) { RaceTestUtils.race(() -> s.request(1), () -> s.request(1)); } RaceTestUtils.race(publisher::complete, publisher::complete); }); latch.await(5, TimeUnit.SECONDS); Assert.assertEquals(capture.get(), 1L); Assert.assertEquals(requested.get(), 20000L); }
@Test public void backpressureDrawbackOnConditionalInTransformTest() { Flux<Integer> publisher = Flux.range(0, 10000); AtomicLong requested = new AtomicLong(); Flux<String> switchTransformed = publisher .doOnRequest(requested::addAndGet) .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf).filter(e -> false))); StepVerifier.create(switchTransformed, 0) .thenRequest(1) .expectComplete() .verify(Duration.ofSeconds(10)); Assert.assertEquals(10001L, requested.get()); }
@Test public void backpressureConditionalTest() { Flux<Integer> publisher = Flux.range(0, 10000); AtomicLong requested = new AtomicLong(); Flux<String> switchTransformed = publisher .doOnRequest(requested::addAndGet) .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))) .filter(e -> false); StepVerifier.create(switchTransformed, 0) .thenRequest(1) .expectComplete() .verify(Duration.ofSeconds(10)); Assert.assertEquals(2L, requested.get()); }
@Test public void backpressureHiddenConditionalTest() { Flux<Integer> publisher = Flux.range(0, 10000); AtomicLong requested = new AtomicLong(); Flux<String> switchTransformed = publisher .doOnRequest(requested::addAndGet) .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf).hide())) .filter(e -> false); StepVerifier.create(switchTransformed, 0) .thenRequest(1) .expectComplete() .verify(Duration.ofSeconds(10)); Assert.assertEquals(10001L, requested.get()); }
@Test public void shouldBeAbleToBeCancelledProperly() { TestPublisher<Integer> publisher = TestPublisher.createCold(); Flux<String> switchTransformed = publisher .flux() .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); publisher.next(1); StepVerifier.create(switchTransformed, 0).thenCancel().verify(Duration.ofSeconds(10)); publisher.assertCancelled(); publisher.assertWasRequested(); }
@Test public void shouldBeAbleToCatchDiscardedElement() { TestPublisher<Integer> publisher = TestPublisher.createCold(); Integer[] discarded = new Integer[1]; Flux<String> switchTransformed = publisher .flux() .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))) .doOnDiscard(Integer.class, e -> discarded[0] = e); publisher.next(1); StepVerifier.create(switchTransformed, 0).thenCancel().verify(Duration.ofSeconds(10)); publisher.assertCancelled(); publisher.assertWasRequested(); Assert.assertArrayEquals(new Integer[] {1}, discarded); }
@Test public void shouldBeAbleToCatchDiscardedElementInCaseOfConditional() { TestPublisher<Integer> publisher = TestPublisher.createCold(); Integer[] discarded = new Integer[1]; Flux<String> switchTransformed = publisher .flux() .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))) .filter(t -> true) .doOnDiscard(Integer.class, e -> discarded[0] = e); publisher.next(1); StepVerifier.create(switchTransformed, 0).thenCancel().verify(Duration.ofSeconds(10)); publisher.assertCancelled(); publisher.assertWasRequested(); Assert.assertArrayEquals(new Integer[] {1}, discarded); } }
@Test public void shouldErrorOnOverflowTest() { TestPublisher<Long> publisher = TestPublisher.createCold(); Flux<String> switchTransformed = publisher .flux() .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); publisher.next(1L); StepVerifier.create(switchTransformed, 0) .thenRequest(1) .expectNext("1") .then(() -> publisher.next(2L)) .expectError() .verify(Duration.ofSeconds(10)); publisher.assertWasRequested(); publisher.assertNoRequestOverflow(); }
@Test public void backpressureTest() { TestPublisher<Long> publisher = TestPublisher.createCold(); AtomicLong requested = new AtomicLong(); Flux<String> switchTransformed = publisher .flux() .doOnRequest(requested::addAndGet) .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); publisher.next(1L); StepVerifier.create(switchTransformed, 0) .thenRequest(1) .expectNext("1") .thenRequest(1) .then(() -> publisher.next(2L)) .expectNext("2") .then(publisher::complete) .expectComplete() .verify(Duration.ofSeconds(10)); publisher.assertWasRequested(); publisher.assertNoRequestOverflow(); Assert.assertEquals(2L, requested.get()); }
.transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.subscriberContext(Context.of("a", "b"))));
@Test public void shouldNotHangWhenOneElementUpstream() { TestPublisher<Long> publisher = TestPublisher.createCold(); Flux<String> switchTransformed = publisher .flux() .transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) -> innerFlux.map(String::valueOf).subscriberContext(Context.of("a", "b")))) .subscriberContext(Context.of("a", "c")) .subscriberContext(Context.of("c", "d")); publisher.next(1L); publisher.complete(); StepVerifier.create(switchTransformed, 0) .thenRequest(1) .expectNext("1") .expectComplete() .verify(Duration.ofSeconds(10)); publisher.assertWasRequested(); publisher.assertNoRequestOverflow(); }
@Test public void shouldReturnCorrectContextOnEmptySource() { Flux<Long> switchTransformed = Flux.<Long>empty() .transform(flux -> new SwitchTransformFlux<>(flux, (first, innerFlux) -> innerFlux)) .subscriberContext(Context.of("a", "c")) .subscriberContext(Context.of("c", "d")); StepVerifier.create(switchTransformed, 0) .expectSubscription() .thenRequest(1) .expectAccessibleContext() .contains("a", "c") .contains("c", "d") .then() .expectComplete() .verify(); }
.transform( flux -> new SwitchTransformFlux<>( flux, (first, innerFlux) ->
@Override public Flux<Payload> requestChannel(Publisher<Payload> payloads) { return new SwitchTransformFlux<>( payloads, (payload, flux) -> { try { ByteBuf metadata = payload.sliceMetadata(); String service = Metadata.getService(metadata); RSocketRpcService rsocketService = registeredServices.get(service); if (rsocketService == null) { ReferenceCountUtil.safeRelease(payload); return Flux.error(new ServiceNotFound(service)); } return rsocketService.requestChannel(payload, flux); } catch (Throwable t) { ReferenceCountUtil.safeRelease(payload); return Flux.error(t); } }); } }