package com.rackspacecloud.blueflood.service;
import com.rackspacecloud.blueflood.types.Points;
import com.rackspacecloud.blueflood.types.Rollup;
import com.rackspacecloud.blueflood.types.RollupType;
import com.rackspacecloud.blueflood.types.SimpleNumber;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Matchers;
import java.io.IOException;
import java.util.concurrent.ThreadPoolExecutor;
import static org.mockito.Mockito.*;
public class RollupBatchWriterTest {
ThreadPoolExecutor executor;
RollupExecutionContext ctx;
RollupBatchWriter rbw;
@Before
public void setUp() {
executor = mock(ThreadPoolExecutor.class);
ctx = mock(RollupExecutionContext.class);
rbw = new RollupBatchWriter(executor, ctx);
}
@Test
public void enqueueIncrementsWriterCounter() {
// given
SingleRollupWriteContext srwc = mock(SingleRollupWriteContext.class);
// when
rbw.enqueueRollupForWrite(srwc);
// then
verify(ctx).incrementWriteCounter();
verifyNoMoreInteractions(ctx);
verifyZeroInteractions(srwc);
}
@Test
public void enqueuingLessThanMinSizeDoesNotTriggerBatching() {
// given
SingleRollupWriteContext srwc1 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc2 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc3 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc4 = mock(SingleRollupWriteContext.class);
// ROLLUP_BATCH_MIN_SIZE default value is 5
// when
rbw.enqueueRollupForWrite(srwc1);
rbw.enqueueRollupForWrite(srwc2);
rbw.enqueueRollupForWrite(srwc3);
rbw.enqueueRollupForWrite(srwc4);
// then
verify(ctx, times(4)).incrementWriteCounter();
verifyNoMoreInteractions(ctx);
verifyZeroInteractions(srwc1);
verifyZeroInteractions(srwc2);
verifyZeroInteractions(srwc3);
verifyZeroInteractions(srwc4);
verifyZeroInteractions(executor);
}
@Test
public void enqueuingMinSizeTriggersCheckOnExecutor() {
// given
// if active count == pool size, the RollupBatchWriter will think the
// thread pool is saturated, and not drain
doReturn(1).when(executor).getActiveCount();
doReturn(1).when(executor).getPoolSize();
SingleRollupWriteContext srwc1 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc2 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc3 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc4 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc5 = mock(SingleRollupWriteContext.class);
// ROLLUP_BATCH_MIN_SIZE default value is 5
// when
rbw.enqueueRollupForWrite(srwc1);
rbw.enqueueRollupForWrite(srwc2);
rbw.enqueueRollupForWrite(srwc3);
rbw.enqueueRollupForWrite(srwc4);
rbw.enqueueRollupForWrite(srwc5);
// then
verify(ctx, times(5)).incrementWriteCounter();
verifyNoMoreInteractions(ctx);
verifyZeroInteractions(srwc1);
verifyZeroInteractions(srwc2);
verifyZeroInteractions(srwc3);
verifyZeroInteractions(srwc4);
verifyZeroInteractions(srwc5);
// if the queue size >= min size, then the executor will be queried
verify(executor).getActiveCount();
verify(executor).getPoolSize();
verifyNoMoreInteractions(executor);
}
@Test
public void enqueuingMinSizeAndThreadPoolNotSaturatedTriggersBatching() throws Exception {
// given
// if active count < pool size, the RollupBatchWriter will think the
// thread pool is NOT saturated, and start batching
doReturn(0).when(executor).getActiveCount();
doReturn(1).when(executor).getPoolSize();
SingleRollupWriteContext srwc1 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc2 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc3 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc4 = mock(SingleRollupWriteContext.class);
SingleRollupWriteContext srwc5 = mock(SingleRollupWriteContext.class);
// ROLLUP_BATCH_MIN_SIZE default value is 5
Points<SimpleNumber> points = new Points<SimpleNumber>();
Rollup rollup = Rollup.BasicFromRaw.compute(points);
doReturn(rollup).when(srwc1).getRollup();
doReturn(rollup).when(srwc2).getRollup();
doReturn(rollup).when(srwc3).getRollup();
doReturn(rollup).when(srwc4).getRollup();
doReturn(rollup).when(srwc5).getRollup();
// when
rbw.enqueueRollupForWrite(srwc1);
rbw.enqueueRollupForWrite(srwc2);
rbw.enqueueRollupForWrite(srwc3);
rbw.enqueueRollupForWrite(srwc4);
rbw.enqueueRollupForWrite(srwc5);
// then
verify(ctx, times(5)).incrementWriteCounter();
verifyNoMoreInteractions(ctx);
// if the queue size >= min size, then the executor will be queried
verify(executor).getActiveCount();
verify(executor).getPoolSize();
verify(executor).execute(Matchers.<Runnable>any());
verifyNoMoreInteractions(executor);
}
@Test
public void enqueuingMaxSizeTriggersBatching() throws Exception {
// given
// if active count == pool size, the RollupBatchWriter will think the
// thread pool is saturated, and not drain
doReturn(1).when(executor).getActiveCount();
doReturn(1).when(executor).getPoolSize();
SingleRollupWriteContext[] srwcs = new SingleRollupWriteContext[100];
int i;
for (i = 0; i < 100; i++) {
srwcs[i] = mock(SingleRollupWriteContext.class);
Points<SimpleNumber> points = new Points<SimpleNumber>();
Rollup rollup = Rollup.BasicFromRaw.compute(points);
doReturn(rollup).when(srwcs[i]).getRollup();
}
// ROLLUP_BATCH_MAX_SIZE default value is 100
// when
for (i = 0; i < 100; i++) {
rbw.enqueueRollupForWrite(srwcs[i]);
}
// then
verify(ctx, times(100)).incrementWriteCounter();
verifyNoMoreInteractions(ctx);
// if the queue size >= min size, then the executor will be queried
verify(executor, times(96)).getActiveCount(); // ROLLUP_BATCH_MAX_SIZE - ROLLUP_BATCH_MIN_SIZE + 1
verify(executor, times(96)).getPoolSize();
verify(executor).execute(Matchers.<Runnable>any());
verifyNoMoreInteractions(executor);
}
@Test
public void drainBatchWithNoItemsDoesNotTriggerBatching() {
// when
rbw.drainBatch();
// then
verifyZeroInteractions(ctx);
verifyZeroInteractions(executor);
}
@Test
public void drainBatchWithSingleItemTriggersBatching() throws Exception {
// given
SingleRollupWriteContext srwc = mock(SingleRollupWriteContext.class);
Points<SimpleNumber> points = new Points<SimpleNumber>();
Rollup rollup = Rollup.BasicFromRaw.compute(points);
doReturn(rollup).when(srwc).getRollup();
rbw.enqueueRollupForWrite(srwc);
// when
rbw.drainBatch();
// then
verify(ctx).incrementWriteCounter(); // this invocation due to setup
verifyNoMoreInteractions(ctx);
verify(executor).execute(Matchers.<Runnable>any());
verifyNoMoreInteractions(executor);
}
}