package io.smallrye.mutiny.operators.multi; import static org.assertj.core.api.Assertions.assertThat; import java.io.IOException; import java.time.Duration; import java.util.List; import org.testng.annotations.Test; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.operators.multi.processors.BroadcastProcessor; import io.smallrye.mutiny.operators.multi.processors.UnicastProcessor; import io.smallrye.mutiny.subscription.BackPressureFailure; import io.smallrye.mutiny.test.MultiAssertSubscriber; public class MultiToHotStreamTest { @Test public void testWithTwoSubscribers() { UnicastProcessor<String> processor = UnicastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); processor.onNext("two"); processor.onNext("three"); MultiAssertSubscriber<String> subscriber2 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("four"); processor.onComplete(); subscriber1 .assertReceived("one", "two", "three", "four") .assertCompletedSuccessfully(); subscriber2 .assertReceived("four") .assertCompletedSuccessfully(); } @Test public void testSubscriptionAfterCompletion() { BroadcastProcessor<String> processor = BroadcastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); processor.onNext("two"); processor.onNext("three"); MultiAssertSubscriber<String> subscriber2 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onComplete(); MultiAssertSubscriber<String> subscriber3 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); subscriber1 .assertReceived("one", "two", "three") .assertCompletedSuccessfully(); subscriber2 .assertHasNotReceivedAnyItem() .assertCompletedSuccessfully(); subscriber3 .assertHasNotReceivedAnyItem() .assertCompletedSuccessfully(); } @Test public void testSubscriptionAfterFailure() { BroadcastProcessor<String> processor = BroadcastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); processor.onNext("two"); processor.onNext("three"); MultiAssertSubscriber<String> subscriber2 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onError(new Exception("boom")); MultiAssertSubscriber<String> subscriber3 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); subscriber1 .assertReceived("one", "two", "three") .assertHasFailedWith(Exception.class, "boom"); subscriber2 .assertHasNotReceivedAnyItem() .assertHasFailedWith(Exception.class, "boom"); subscriber3 .assertHasNotReceivedAnyItem() .assertHasFailedWith(Exception.class, "boom"); } @Test public void testFailureAfterCompletion() { BroadcastProcessor<Integer> processor = BroadcastProcessor.create(); Multi<Integer> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<Integer> subscriber = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext(1); processor.onNext(2); processor.onComplete(); processor.onError(new Exception("boom")); subscriber.assertCompletedSuccessfully().assertReceived(1, 2); } @Test public void testNoItemAfterCancellation() { BroadcastProcessor<String> processor = BroadcastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); subscriber1.assertReceived("one"); MultiAssertSubscriber<String> subscriber2 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("two"); subscriber1.assertReceived("one", "two"); subscriber2.assertReceived("two"); subscriber1.cancel(); processor.onNext("three"); subscriber1.assertNotTerminated().assertReceived("one", "two"); subscriber2.assertReceived("two", "three"); processor.onComplete(); subscriber2.assertReceived("two", "three").assertCompletedSuccessfully(); subscriber1.assertNotTerminated().assertReceived("one", "two"); processor.onNext("four"); subscriber2.assertReceived("two", "three").assertCompletedSuccessfully(); subscriber1.assertNotTerminated().assertReceived("one", "two"); } @Test public void testResubscription() { BroadcastProcessor<String> processor = BroadcastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); subscriber1.assertReceived("one"); subscriber1.cancel(); processor.onNext("two"); processor.subscribe(subscriber1); processor.onNext("three"); processor.onComplete(); subscriber1.assertReceived("one", "three") .assertCompletedSuccessfully(); } @Test public void testResubscriptionAfterCompletion() { BroadcastProcessor<String> processor = BroadcastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); subscriber1.assertReceived("one"); subscriber1.cancel(); processor.onNext("two"); processor.onComplete(); processor.subscribe(subscriber1); subscriber1.assertReceived("one") .assertCompletedSuccessfully(); } @Test public void testResubscriptionAfterFailure() { BroadcastProcessor<String> processor = BroadcastProcessor.create(); Multi<String> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<String> subscriber1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); processor.onNext("one"); subscriber1.assertReceived("one"); subscriber1.cancel(); processor.onNext("two"); processor.onError(new IOException("boom")); processor.subscribe(subscriber1); subscriber1.assertReceived("one") .assertHasFailedWith(IOException.class, "boom"); } @Test public void testWhenSubscriberDoesNotHaveRequestedEnough() { BroadcastProcessor<Integer> processor = BroadcastProcessor.create(); Multi<Integer> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<Integer> s1 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(10)); MultiAssertSubscriber<Integer> s2 = multi.subscribe() .withSubscriber(MultiAssertSubscriber.create(4)); for (int i = 0; i < 10; i++) { processor.onNext(i); } processor.onComplete(); s1.assertCompletedSuccessfully() .assertReceived(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); s2.assertHasFailedWith(BackPressureFailure.class, "request"); } @Test public void testWithFlatMap() { BroadcastProcessor<Integer> processor = BroadcastProcessor.create(); Multi<Integer> multi = processor.map(s -> s).transform().toHotStream(); MultiAssertSubscriber<Integer> subscriber = MultiAssertSubscriber.create(10); multi .onItem().produceMulti(i -> processor).withRequests(10).merge() .subscribe().withSubscriber(subscriber); processor.onNext(1); processor.onNext(2); processor.onNext(3); processor.onNext(4); processor.onComplete(); subscriber.assertReceived(2, 3, 3, 4, 4, 4) .assertCompletedSuccessfully(); } @Test public void testMakingTicksAHotStream() throws InterruptedException { Multi<Long> ticks = Multi.createFrom().ticks().every(Duration.ofMillis(1)) .transform().byTakingFirstItems(100) .transform().toHotStream(); Thread.sleep(50); // NOSONAR MultiAssertSubscriber<Long> subscriber = ticks.subscribe() .withSubscriber(MultiAssertSubscriber.create(Long.MAX_VALUE)) .await(Duration.ofSeconds(10)) .assertCompletedSuccessfully(); List<Long> items = subscriber.items(); assertThat(items).doesNotContain(0L, 1L, 2L, 3L, 4L); } }