package it.tdlight.reactiveapi.test; import com.google.common.net.HostAndPort; import it.tdlight.reactiveapi.EventConsumer; import it.tdlight.reactiveapi.EventProducer; import it.tdlight.reactiveapi.Timestamped; import it.unimi.dsi.fastutil.ints.IntArrayList; import java.time.Duration; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public abstract class TestChannel { protected HostAndPort hostAndPort; protected EventConsumer consumer; protected EventProducer producer; protected IntArrayList data; @BeforeEach public void beforeEach() { hostAndPort = HostAndPort.fromParts("localhost", 25689); consumer = createConsumer(hostAndPort, false); producer = createProducer(hostAndPort, false); data = new IntArrayList(100); for (int i = 0; i < 100; i++) { data.add(i); } } public abstract EventConsumer createConsumer(HostAndPort hostAndPort, boolean bomb); public abstract EventProducer createProducer(HostAndPort hostAndPort, boolean bomb); @AfterEach public void afterEach() { producer.close(); } @Test public void testSimple() { Mono sender = producer .sendMessages(Flux.fromIterable(data).map(Integer::toUnsignedString)) .then(Mono.empty()); Mono receiver = consumer .consumeMessages() .map(Timestamped::data) .map(Integer::parseUnsignedInt) .collect(Collectors.toCollection(IntArrayList::new)); var response = Flux .merge(isServerSender() ? (List.of(sender, receiver)) : List.of(receiver, sender)) .blockLast(); Assertions.assertEquals(response, data); System.out.println(response); } @Test public void testException() { Mono sender = producer .sendMessages(Flux.concat( Flux.fromIterable(data).map(Integer::toUnsignedString), Mono.error(new FakeException()) )) .then(Mono.empty()); Mono receiver = consumer .consumeMessages() .map(Timestamped::data) .map(Integer::parseUnsignedInt) .collect(Collectors.toCollection(IntArrayList::new)); Assertions.assertThrows(Exception.class, () -> Flux .merge(isServerSender() ? (List.of(sender, receiver)) : List.of(receiver, sender)) .blockLast()); } @Test public void testEmpty() { Mono sender = producer .sendMessages(Flux.empty()) .then(Mono.empty()); Mono receiver = consumer .consumeMessages() .map(Timestamped::data) .map(Integer::parseUnsignedInt) .collect(Collectors.toCollection(IntArrayList::new)); var data = Flux .merge(isServerSender() ? (List.of(sender, receiver)) : List.of(receiver, sender)) .blockLast(); Assertions.assertNotNull(data); Assertions.assertTrue(data.isEmpty()); } @Test public void testSimpleOneByOne() { var sender = producer.sendMessages(Flux.fromIterable(data).map(Integer::toUnsignedString)); var receiver = consumer .consumeMessages() .limitRate(1) .map(Timestamped::data) .map(Integer::parseUnsignedInt) .collect(Collectors.toCollection(IntArrayList::new)); var response = Flux .merge(isServerSender() ? (List.of(sender, receiver)) : List.of(receiver, sender)) .blockLast(); Assertions.assertEquals(response, data); System.out.println(response); } @Test public void testCancel() { var sender = producer.sendMessages(Flux.fromIterable(data).map(Integer::toUnsignedString)); var receiver = consumer .consumeMessages() .map(Timestamped::data) .map(Integer::parseUnsignedInt) .take(50, true) .collect(Collectors.toCollection(IntArrayList::new)); var response = Flux .merge(isServerSender() ? (List.of(sender, receiver)) : List.of(receiver, sender)) .blockLast(); data.removeElements(50, 100); Assertions.assertEquals(response, data); System.out.println(response); } @Test public void testConsumeDelay() { var sender = producer .sendMessages(Flux.fromIterable(data).map(Integer::toUnsignedString)); var receiver = consumer .consumeMessages() .limitRate(1) .map(Timestamped::data) .map(Integer::parseUnsignedInt) .concatMap(item -> item == 15 ? Mono.just(item).delaySubscription(Duration.ofSeconds(8)) : Mono.just(item)) .collect(Collectors.toCollection(IntArrayList::new)); var response = Flux .merge(isServerSender() ? List.of(sender, receiver) : List.of(receiver, sender)) .blockLast(); Assertions.assertEquals(response, data); System.out.println(response); } @Test public void testProduceDelay() { var sender = producer .sendMessages(Flux.fromIterable(data) .concatMap(item -> item == 15 ? Mono.just(item).delaySubscription(Duration.ofSeconds(8)) : Mono.just(item)) .map(Integer::toUnsignedString)); var receiver = consumer .consumeMessages() .limitRate(1) .map(Timestamped::data) .map(Integer::parseUnsignedInt) .collect(Collectors.toCollection(IntArrayList::new)); var response = Flux .merge(isServerSender() ? List.of(sender, receiver) : List.of(receiver, sender)) .blockLast(); Assertions.assertEquals(response, data); System.out.println(response); } @Test public void testConsumeMidCancel() { var dataFlux = Flux.fromIterable(data).publish().autoConnect(); Mono sender = producer .sendMessages(dataFlux.map(Integer::toUnsignedString)) .then(Mono.empty()); var receiver1 = consumer .consumeMessages() .limitRate(1) .map(Timestamped::data) .map(Integer::parseUnsignedInt) .take(10, true) .collect(Collectors.toCollection(IntArrayList::new)); var receiver2 = consumer .consumeMessages() .limitRate(1) .map(Timestamped::data) .map(Integer::parseUnsignedInt) .collect(Collectors.toCollection(IntArrayList::new)); Flux part1 = Flux .merge((isServerSender() ? sender : receiver1), isServerSender() ? receiver1 : sender); Flux part2 = Flux .merge((isServerSender() ? sender : receiver2), isServerSender() ? receiver2 : sender); var response = Flux.concat(part1, part2).reduce((a, b) -> { a.addAll(b); return a; }).block(); Assertions.assertEquals(response, data); System.out.println(response); } public abstract boolean isServerSender(); }