package io.vertx.test.core; import io.vertx.core.Context; import io.vertx.core.Vertx; import io.vertx.core.eventbus.DeliveryOptions; import io.vertx.core.eventbus.EventBus; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.eventbus.MessageProducer; import org.junit.Test; import java.util.LinkedList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; /** * @author <a href="http://tfox.org">Tim Fox</a> */ public class EventBusFlowControlTest extends VertxTestBase { protected EventBus eb; @Test public void testFlowControl() { MessageProducer<String> prod = eb.sender("some-address"); int numBatches = 1000; int wqms = 2000; prod.setWriteQueueMaxSize(wqms); MessageConsumer<String> consumer = eb.consumer("some-address"); AtomicInteger cnt = new AtomicInteger(); consumer.handler(msg -> { int c = cnt.incrementAndGet(); if (c == numBatches * wqms) { testComplete(); } }); vertx.runOnContext(v -> { sendBatch(prod, wqms, numBatches, 0); }); await(); } @Test public void testFlowControlWithOptions() { MessageProducer<String> prod = eb.sender("some-address"); prod.deliveryOptions(new DeliveryOptions().addHeader("foo", "bar")); int numBatches = 1000; int wqms = 2000; prod.setWriteQueueMaxSize(wqms); MessageConsumer<String> consumer = eb.consumer("some-address"); AtomicInteger cnt = new AtomicInteger(); consumer.handler(msg -> { int c = cnt.incrementAndGet(); if (c == numBatches * wqms) { testComplete(); } }); vertx.runOnContext(v -> { sendBatch(prod, wqms, numBatches, 0); }); await(10, TimeUnit.SECONDS); } private void sendBatch(MessageProducer<String> prod, int batchSize, int numBatches, int batchNumber) { while (batchNumber < numBatches) { for (int i = 0; i < batchSize; i++) { prod.send("message-" + i); } if (prod.writeQueueFull()) { int nextBatch = batchNumber + 1; prod.drainHandler(v -> { sendBatch(prod, batchSize, numBatches, nextBatch); }); break; } else { batchNumber++; } } } @Test public void testFlowControlPauseConsumer() { MessageProducer<String> prod = eb.sender("some-address"); int numBatches = 10; int wqms = 100; prod.setWriteQueueMaxSize(wqms); MessageConsumer<String> consumer = eb.consumer("some-address"); AtomicInteger cnt = new AtomicInteger(); AtomicBoolean paused = new AtomicBoolean(); consumer.handler(msg -> { assertFalse(paused.get()); int c = cnt.incrementAndGet(); if (c == numBatches * wqms) { testComplete(); } if (c % 100 == 0) { consumer.pause(); paused.set(true); vertx.setTimer(100, tid -> { paused.set(false); consumer.resume(); }); } }); sendBatch(prod, wqms, numBatches, 0); await(); } @Test public void testFlowControlNoConsumer() { MessageProducer<String> prod = eb.sender("some-address"); int wqms = 2000; prod.setWriteQueueMaxSize(wqms); boolean drainHandlerSet = false; for (int i = 0; i < wqms * 2; i++) { prod.send("message-" + i); if (prod.writeQueueFull() && !drainHandlerSet) { prod.drainHandler(v -> { fail("Should not be called"); }); drainHandlerSet = true; } } assertTrue(drainHandlerSet); vertx.setTimer(500, tid -> testComplete()); await(); } @Test public void testResumePausedProducer() { BlockingQueue<Integer> sequence = new LinkedBlockingQueue<>(); AtomicReference<Context> handlerContext = new AtomicReference<>(); MessageConsumer<Integer> consumer = eb.consumer("some-address", msg -> { if (sequence.isEmpty()) { handlerContext.set(Vertx.currentContext()); } else { assertEquals(Vertx.currentContext(), handlerContext.get()); } sequence.add(msg.body()); }); consumer.pause(); MessageProducer<Integer> prod = eb.sender("some-address"); LinkedList<Integer> expected = new LinkedList<>(); int count = 0; while (!prod.writeQueueFull()) { int val = count++; expected.add(val); prod.send(val); } consumer.resume(); assertWaitUntil(() -> !prod.writeQueueFull()); int theCount = count; assertWaitUntil(() -> sequence.size() == theCount); while (expected.size() > 0) { assertEquals(expected.removeFirst(), sequence.poll()); } assertNotNull(handlerContext.get()); } @Override public void setUp() throws Exception { super.setUp(); eb = vertx.eventBus(); } }