package org.sef4j.core.helpers.senders;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.sef4j.core.api.EventSender;
public class BulkAsyncSenderTest {
private static class E {
public final int id;
private E(int id) {
this.id = id;
}
@Override
public String toString() {
return "E [" + id + "]";
}
}
protected static class InMemoryBulkEventSender<T> implements EventSender<T> {
private List<Collection<T>> eventsBulks = new ArrayList<Collection<T>>();
@Override
public void sendEvent(T event) {
eventsBulks.add(Collections.singleton(event));
}
@Override
public void sendEvents(Collection<T> events) {
List<T> eventsCopy = new ArrayList<T>(events); // copy safety
eventsBulks.add(eventsCopy);
}
public List<Collection<T>> clearAndGet() {
List<Collection<T>> res = eventsBulks;
this.eventsBulks = new ArrayList<Collection<T>>();
return res;
}
}
protected InMemoryBulkEventSender<E> targetSender = new InMemoryBulkEventSender<E>();
protected int maxBulkEventsCount = 10;
protected BulkAsyncSender<E> sut = new BulkAsyncSender.Builder<E>()
.flushPeriod(60) // flush after 60 seconds
.maxBulkEventsCount(maxBulkEventsCount)
.maxBulkByteLength(4000)
.build(targetSender);
@Test
public void testSend_maxBulkEventsCount_flushInThread() throws InterruptedException {
doTestSend_maxBulkEventsCount_thread(true);
}
@Test
public void testSend_maxBulkEventsCount_flushAsync() throws InterruptedException {
doTestSend_maxBulkEventsCount_thread(false);
}
protected void doTestSend_maxBulkEventsCount_thread(boolean flushInCurrentThread) throws InterruptedException {
// Prepare
sut.setFlushFilledBulkInCurrentThread(flushInCurrentThread);
int bulksCount = 2;
int extraEventCount = 3;
List<E> eList = new ArrayList<E>();
for(int i = 0; i < bulksCount*maxBulkEventsCount+extraEventCount; i++) {
eList.add(new E(i));
}
// Perform
for(int i = 0; i < bulksCount*maxBulkEventsCount+extraEventCount; i++) {
sut.sendEvent(eList.get(i));
}
// Post-check
// check bulks
// need to wait few millis for async "immediate" flush on other thread!
waitImmediateFlush(sut, false);
Assert.assertEquals(0, sut.getCurrentAsyncEventsBulksQueueSize());
Assert.assertEquals(extraEventCount, sut.getCurrentBufferedEventsSize());
List<Collection<E>> resBulks = targetSender.clearAndGet();
Assert.assertEquals(bulksCount, resBulks.size());
int index = 0;
for(Collection<E> bulk : resBulks) {
Assert.assertEquals(maxBulkEventsCount, bulk.size());
for(E event : bulk) {
Assert.assertEquals(eList.get(index), event);
index++;
}
}
// check still buffered
int bufferedEventsSize = sut.getCurrentBufferedEventsSize();
Assert.assertEquals(extraEventCount, bufferedEventsSize);
// now flush...
// Perform
sut.flush(true, true);
// Post-check
waitImmediateFlush(sut, true);
Assert.assertEquals(0, sut.getCurrentBufferedEventsSize());
resBulks = targetSender.clearAndGet();
Assert.assertEquals(1, resBulks.size());
Collection<E> bulk = resBulks.get(0);
Assert.assertEquals(extraEventCount, bulk.size());
for(E event : bulk) {
Assert.assertEquals(eList.get(index), event);
index++;
}
}
private void waitImmediateFlush(BulkAsyncSender<E> sut, boolean flushPartialBulk) {
int remain = sut.getCurrentAsyncEventsBulksQueueSize();
if (remain != 0) {
sut.waitAsyncEventBulksQueueFlushed(3, 100);
remain = sut.getCurrentAsyncEventsBulksQueueSize();
}
if (flushPartialBulk) {
// ? should not occurs
sut.flush(false, flushPartialBulk);
}
}
}