package com.netflix.eventbus.impl;
import com.netflix.eventbus.spi.Subscribe;
import com.netflix.eventbus.spi.SubscriberConfigProvider;
import com.netflix.eventbus.utils.EventBusUtils;
import junit.framework.Assert;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author Nitesh Kant (nkant@netflix.com)
*/
public class ConsumerQueueFullTest {
@Test
public void testQueueFull() throws Exception {
BlockIndefinetly mySub = new BlockIndefinetly();
Method subMethod = mySub.getClass().getMethod("subMe", String.class);
MyConsumerQueueSupplier qSupplier = new MyConsumerQueueSupplier(false);
EventConsumer consumer = new EventConsumer(subMethod, mySub, null, String.class, qSupplier);
consumer.shutdown(); // Just to make the poller stop.
qSupplier.resetCounters();
for (int j=0; j < 5;j++) {
consumer.enqueue("event" + j);
}
Assert.assertEquals("Unexpected queue offers ", 8, qSupplier.offers.get());
Assert.assertEquals("Unexpected queue non blocking takes", 3, qSupplier.nonBlockingTake.get());
Assert.assertEquals("Unexpected queue clear", 0, qSupplier.clear.get());
Assert.assertEquals("Consumer retry stats not correct.", 3,
consumer.getStats().QUEUE_OFFER_RETRY_COUNTER.getValue().longValue());
Assert.assertEquals("Consumer queue size stats not correct.", 2, consumer.getStats().QUEUE_SIZE_COUNTER.get());
}
@Test
public void testRetryFail() throws Exception {
BlockIndefinetly mySub = new BlockIndefinetly();
Method subMethod = mySub.getClass().getMethod("subMe", String.class);
MyConsumerQueueSupplier qSupplier = new MyConsumerQueueSupplier(true);
EventConsumer consumer = new EventConsumer(subMethod, mySub, null, String.class, qSupplier);
consumer.shutdown(); // Just to make the poller stop.
qSupplier.resetCounters();
for (int j=0; j < 3;j++) {
consumer.enqueue("event" + j);
}
Assert.assertEquals("Unexpected queue offers ", 8, qSupplier.offers.get());
Assert.assertEquals("Unexpected queue non blocking takes", 5, qSupplier.nonBlockingTake.get());
Assert.assertEquals("Unexpected queue clear", 0, qSupplier.clear.get());
Assert.assertEquals("Consumer retry stats not correct.", 5,
consumer.getStats().QUEUE_OFFER_RETRY_COUNTER.getValue().longValue());
Assert.assertEquals("Consumer queue size stats not correct.", 2, consumer.getStats().QUEUE_SIZE_COUNTER.get());
Assert.assertEquals("Consumer queue event rejected stats not correct.", 1,
consumer.getStats().EVENT_ENQUEUE_REJECTED_COUNTER.getValue().longValue());
}
private static class MyConsumerQueueSupplier implements EventBusImpl.ConsumerQueueSupplier {
private LinkedBlockingQueue q;
private AtomicInteger offers = new AtomicInteger();
private AtomicInteger nonBlockingTake = new AtomicInteger();
private AtomicInteger blockingTake = new AtomicInteger();
private AtomicInteger clear = new AtomicInteger();
private boolean ignoreNonBlockingTakes;
private MyConsumerQueueSupplier(boolean ignoreNonBlockingTakes) {
this.ignoreNonBlockingTakes = ignoreNonBlockingTakes;
}
@Override
public ConsumerQueue get(Method subscriberMethod, SubscriberConfigProvider.SubscriberConfig subscriberConfig,
AtomicLong queueSizeCounter) {
return new MyConsumerQueue(subscriberConfig, queueSizeCounter);
}
void resetCounters() {
offers.set(0);
nonBlockingTake.set(0);
blockingTake.set(0);
clear.set(0);
}
@SuppressWarnings("unchecked")
private class MyConsumerQueue implements ConsumerQueue {
private AtomicLong queueSizeCounter;
private MyConsumerQueue(SubscriberConfigProvider.SubscriberConfig subscribe, AtomicLong queueSizeCounter) {
this.queueSizeCounter = queueSizeCounter;
q = new LinkedBlockingQueue(EventBusUtils.getQueueSize(subscribe));
}
@Override
public boolean offer(Object event) {
offers.incrementAndGet();
if (q.offer(event)) {
queueSizeCounter.incrementAndGet();
return true;
}
return false;
}
@Override
public Object nonBlockingTake() {
nonBlockingTake.incrementAndGet();
if (ignoreNonBlockingTakes) {
return null;
}
Object poll = q.poll();
if (null != poll) {
queueSizeCounter.decrementAndGet();
}
return poll;
}
@Override
public Object blockingTake() throws InterruptedException {
blockingTake.incrementAndGet();
Object take = q.take();
queueSizeCounter.decrementAndGet();
return take;
}
@Override
public void clear() {
clear.incrementAndGet();
q.clear();
queueSizeCounter.set(0);
}
}
}
public class BlockIndefinetly {
private final Object dieWaiting = new Object();
@Subscribe(queueSize = 2,batchingStrategy = Subscribe.BatchingStrategy.None)
public void subMe(String event) {
synchronized (dieWaiting) {
try {
dieWaiting.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}