package com.codecademy.eventhub.index;
import com.google.inject.Injector;
import com.codecademy.eventhub.integration.GuiceTestCase;
import org.junit.Assert;
import org.junit.Test;
import javax.inject.Provider;
import java.nio.ByteBuffer;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
public class UserEventIndexTest extends GuiceTestCase {
@Test
public void testAll() throws Exception {
Provider<UserEventIndex> dmaUserEventIndexProvider = getDmaUserEventIndexProvider();
UserEventIndex userEventIndex = dmaUserEventIndexProvider.get();
userEventIndex.addEvent(0, 10);
userEventIndex.addEvent(1, 20);
userEventIndex.addEvent(2, 30);
userEventIndex.addEvent(0, 40);
userEventIndex.addEvent(1, 50);
userEventIndex.addEvent(2, 60);
userEventIndex.addEvent(0, 70);
userEventIndex.addEvent(1, 80);
userEventIndex.addEvent(2, 90);
userEventIndex.addEvent(0, 100);
userEventIndex.addEvent(1, 110);
userEventIndex.addEvent(2, 120);
IdVerificationCallback callback = new IdVerificationCallback(new int[] { 20, 50, 80, 110 });
userEventIndex.enumerateEventIds(1, userEventIndex.getEventOffset(1, 1), Integer.MAX_VALUE, callback);
callback.verify();
callback = new IdVerificationCallback(new int[] { 50, 80, 110 });
userEventIndex.enumerateEventIds(1, userEventIndex.getEventOffset(1, 50), Integer.MAX_VALUE, callback);
callback.verify();
callback = new IdVerificationCallback(new int[] { 20, 50, 80 });
userEventIndex.enumerateEventIds(1, userEventIndex.getEventOffset(1, 20), 3, callback);
callback.verify();
userEventIndex.close();
userEventIndex = dmaUserEventIndexProvider.get();
callback = new IdVerificationCallback(new int[] { 20, 50, 80, 110 });
userEventIndex.enumerateEventIds(1, userEventIndex.getEventOffset(1, 1), Integer.MAX_VALUE, callback);
callback.verify();
callback = new IdVerificationCallback(new int[] { 50, 80, 110 });
userEventIndex.enumerateEventIds(1, userEventIndex.getEventOffset(1, 50), Integer.MAX_VALUE, callback);
callback.verify();
callback = new IdVerificationCallback(new int[] { 20, 50, 80 });
userEventIndex.enumerateEventIds(1, userEventIndex.getEventOffset(1, 20), 3, callback);
callback.verify();
}
private static class IdVerificationCallback implements UserEventIndex.Callback {
private final int[] expectedIds;
private int counter;
public IdVerificationCallback(int[] expectedIds) {
this.expectedIds = expectedIds;
this.counter = 0;
}
@Override
public boolean shouldContinueOnEventId(long eventId) {
Assert.assertEquals(expectedIds[counter++], eventId);
return true;
}
public void verify() {
Assert.assertEquals(expectedIds.length, counter);
}
}
@Test
public void testBlock() throws Exception {
int blockOffset = 10;
long pointer = 2000;
int minId = 5;
ByteBuffer metaDataByteBuffer = ByteBuffer.allocate(UserEventIndex.Block.MetaData.SIZE);
ByteBuffer blockByteBuffer = ByteBuffer.allocate(1000);
long prevBlockPointer = 1000;
long nextBlockPointer = 3000;
UserEventIndex.Block.MetaData metaData = new UserEventIndex.Block.MetaData(metaDataByteBuffer);
UserEventIndex.Block block = new UserEventIndex.Block(metaData, blockByteBuffer);
metaData.setBlockOffset(blockOffset);
metaData.setPointer(pointer);
metaData.setMinId(minId);
metaData.setNextBlockPointer(nextBlockPointer);
metaData.setPrevBlockPointer(prevBlockPointer);
metaData.setNumRecords(0);
long[] records = new long[] { 10, 20, 30 };
for (long record : records) {
block.add(record);
}
Assert.assertEquals(minId, block.getMetaData().getMinId());
Assert.assertEquals(pointer, block.getMetaData().getPointer());
Assert.assertEquals(prevBlockPointer, block.getMetaData().getPrevBlockPointer());
Assert.assertEquals(nextBlockPointer, block.getMetaData().getNextBlockPointer());
for (int i = 0; i < records.length; i++) {
Assert.assertEquals(records[i], block.getRecord(i));
}
Assert.assertEquals(0, block.findOffset(10));
Assert.assertEquals(1, block.findOffset(20));
Assert.assertEquals(2, block.findOffset(25));
Assert.assertEquals(2, block.findOffset(30));
Assert.assertEquals(3, block.findOffset(40));
block = new UserEventIndex.Block(new UserEventIndex.Block.MetaData(metaDataByteBuffer),
blockByteBuffer);
Assert.assertEquals(minId, block.getMetaData().getMinId());
Assert.assertEquals(pointer, block.getMetaData().getPointer());
Assert.assertEquals(prevBlockPointer, block.getMetaData().getPrevBlockPointer());
Assert.assertEquals(nextBlockPointer, block.getMetaData().getNextBlockPointer());
for (int i = 0; i < records.length; i++) {
Assert.assertEquals(records[i], block.getRecord(i));
}
Assert.assertEquals(0, block.findOffset(10));
Assert.assertEquals(1, block.findOffset(20));
Assert.assertEquals(2, block.findOffset(25));
Assert.assertEquals(2, block.findOffset(30));
Assert.assertEquals(3, block.findOffset(40));
}
@Test
public void testIndexEntry() throws Exception {
int numRecords = 1;
long minId = 10L;
int numPointers = 3;
long[] pointers = new long[] { 10L, -1, -1 };
long[] minIds = new long[] { 1L, -1, -1 };
UserEventIndex.IndexEntry indexEntry = new UserEventIndex.IndexEntry(
new AtomicInteger(numRecords), minId, pointers, minIds);
UserEventIndex.IndexEntry.Schema schema = new UserEventIndex.IndexEntry.Schema(
numPointers);
Assert.assertEquals(minId, indexEntry.getMinId());
Assert.assertEquals(numRecords, indexEntry.getNumRecords());
indexEntry.incrementNumRecord();
Assert.assertEquals(numRecords + 1, indexEntry.getNumRecords());
Assert.assertEquals(10L, indexEntry.getPointer(0));
Assert.assertEquals(-1, indexEntry.getPointer(1));
Assert.assertEquals(1L, indexEntry.getMinIdInIndex(0));
Assert.assertEquals(-1, indexEntry.getMinIdInIndex(1));
for (int i = 1; i < 5; i++) {
UserEventIndex.Block.MetaData metaData = new UserEventIndex.Block.MetaData(
ByteBuffer.allocate(UserEventIndex.Block.MetaData.SIZE));
metaData.setBlockOffset(i);
metaData.setPointer(i * 100);
metaData.setMinId(i * 10);
indexEntry.shiftBlock(new UserEventIndex.Block(metaData, null));
}
Assert.assertEquals(400L, indexEntry.getPointer(0));
Assert.assertEquals(300L, indexEntry.getPointer(1));
Assert.assertEquals(200L, indexEntry.getPointer(2));
Assert.assertEquals(40L, indexEntry.getMinIdInIndex(0));
Assert.assertEquals(30L, indexEntry.getMinIdInIndex(1));
Assert.assertEquals(20L, indexEntry.getMinIdInIndex(2));
indexEntry = schema.fromBytes(schema.toBytes(indexEntry));
Assert.assertEquals(minId, indexEntry.getMinId());
Assert.assertEquals(numRecords + 1, indexEntry.getNumRecords());
Assert.assertEquals(400L, indexEntry.getPointer(0));
Assert.assertEquals(300L, indexEntry.getPointer(1));
Assert.assertEquals(200L, indexEntry.getPointer(2));
Assert.assertEquals(40L, indexEntry.getMinIdInIndex(0));
Assert.assertEquals(30L, indexEntry.getMinIdInIndex(1));
Assert.assertEquals(20L, indexEntry.getMinIdInIndex(2));
}
private Provider<UserEventIndex> getDmaUserEventIndexProvider() {
Properties prop = new Properties();
prop.put("eventhub.directory", getTempDirectory());
prop.put("eventhub.usereventindex.numPointersPerIndexEntry", "2");
prop.put("eventhub.usereventindex.numIndexEntryPerFile", "2");
prop.put("eventhub.usereventindex.indexEntryFileCacheSize", "2");
prop.put("eventhub.usereventindex.numRecordsPerBlock", "2");
prop.put("eventhub.usereventindex.numBlocksPerFile", "2");
prop.put("eventhub.usereventindex.blockCacheSize", "2");
Injector injector = createInjectorFor(
prop, new UserEventIndexModule());
return injector.getProvider(UserEventIndex.class);
}
}