package de.hub.emffrag.fragmentation;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import junit.framework.Assert;
import org.eclipse.emf.common.util.URI;
import org.junit.Before;
import org.junit.Test;
import de.hub.emffrag.datastore.DataStoreImpl;
import de.hub.emffrag.datastore.IBaseDataStore;
import de.hub.emffrag.datastore.IBulkInsertExtension;
import de.hub.emffrag.datastore.IDataMap;
import de.hub.emffrag.datastore.IDataStore;
import de.hub.emffrag.datastore.IScanExtension;
import de.hub.emffrag.datastore.InMemoryDataStore;
import de.hub.emffrag.datastore.LongKeyType;
import de.hub.emffrag.datastore.ScanningDataStore;
import de.hub.emffrag.datastore.WriteCachingDataStore;
public abstract class AbstractDataStoreTest {
protected abstract IBaseDataStore createBaseDataStore();
/**
* @return null if no scan extension shall be used. See {@link ScanningDataStore}.
*/
protected IScanExtension createScanExtension() {
return null;
}
/**
* @return null if no bulk insert shall be used. See {@link WriteCachingDataStore}.
*/
protected IBulkInsertExtension createBulkInsertExtension() {
return null;
}
protected abstract URI createURI();
protected IDataStore dataStore;
@Before
public void createDataStore() {
IBaseDataStore baseDataStore = createBaseDataStore();
IScanExtension scanExtension = createScanExtension();
IBulkInsertExtension bulkInsertExtension = createBulkInsertExtension();
URI uri = createURI();
if (scanExtension != null) {
baseDataStore = new ScanningDataStore(baseDataStore, scanExtension);
}
if (bulkInsertExtension != null) {
baseDataStore = new WriteCachingDataStore(baseDataStore, bulkInsertExtension);
}
dataStore = new DataStoreImpl(baseDataStore, uri);
}
@Test
public void testBasicWriteRead() {
for (int i = 0; i < 5000; i++) {
byte[] key = createKey(i);
byte[] value = createValue(i);
write(key, value);
}
for (int i = 0; i < 5000; i++) {
byte[] key = createKey(i);
byte[] value = createValue(i);
read(key, value);
}
for (int i = 5000; i < 10000; i++) {
byte[] key = createKey(i);
InputStream is = dataStore.openInputStream(key);
Assert.assertNull(is);
}
}
private void read(byte[] key, byte[] value) {
InputStream is = dataStore.openInputStream(key);
Assert.assertNotNull(is);
byte[] readValue = new byte[value.length];
try {
is.read(readValue, 0, value.length);
is.close();
} catch (IOException e) {
Assert.fail(e.getClass().getName() + ": " + e.getMessage());
}
Assert.assertEquals(0, InMemoryDataStore.compareBytes(value, readValue));
}
private void write(byte[] key, byte[] value) {
OutputStream os = dataStore.openOutputStream(key);
try {
os.write(value);
os.close();
} catch (Exception e) {
Assert.fail(e.getClass().getName() + ": " + e.getMessage());
}
}
private byte[] createValue(int i) {
return ("testValue" + i).getBytes();
}
@Test
public void testRandomReadWrite() {
Random random = new Random(0);
Map<BigInteger, byte[]> reference = new HashMap<BigInteger, byte[]>();
for (int i = 0; i < 100; i++) {
long randomKey = random.nextLong();
BigInteger bigIntegerKey = BigInteger.valueOf(randomKey);
byte[] key = bigIntegerKey.toByteArray();
byte[] value = createValue(i);
write(key, value);
reference.put(bigIntegerKey, value);
read(key, value);
}
for (Entry<BigInteger, byte[]> entry: reference.entrySet()) {
read(entry.getKey().toByteArray(), entry.getValue());
}
}
@Test
public void testCeiling() {
writePattern();
Assert.assertEquals(BigInteger.valueOf(0), new BigInteger(dataStore.ceiling(createKey(0))));
Assert.assertEquals(BigInteger.valueOf(1), new BigInteger(dataStore.ceiling(createKey(1))));
Assert.assertEquals(BigInteger.valueOf(6), new BigInteger(dataStore.ceiling(createKey(2))));
}
private void writePattern() {
int[] keyPattern = new int[] {0, 1, 6, 10, 20};
for (int key: keyPattern) {
write(createKey(key), createValue(key));
}
}
@Test
public void testFloor() {
writePattern();
Assert.assertEquals(BigInteger.valueOf(0), new BigInteger(dataStore.floor(createKey(0))));
Assert.assertEquals(BigInteger.valueOf(1), new BigInteger(dataStore.floor(createKey(1))));
Assert.assertEquals(BigInteger.valueOf(1), new BigInteger(dataStore.floor(createKey(2))));
}
@Test
public void testCheck() {
writePattern();
Assert.assertFalse(dataStore.check(createKey(0)));
Assert.assertFalse(dataStore.check(createKey(1)));
Assert.assertTrue(dataStore.check(createKey(2)));
Assert.assertTrue(dataStore.check(createKey(2)));
}
@Test
public void testCheckAndCreate() {
writePattern();
Assert.assertFalse(dataStore.checkAndCreate(createKey(0)));
Assert.assertFalse(dataStore.checkAndCreate(createKey(1)));
Assert.assertTrue(dataStore.checkAndCreate(createKey(2)));
Assert.assertFalse(dataStore.checkAndCreate(createKey(2)));
}
@Test
public void testDelete() {
writePattern();
Assert.assertFalse(dataStore.check(createKey(0)));
dataStore.delete(createKey(0));
Assert.assertTrue(dataStore.check(createKey(0)));
Assert.assertEquals(BigInteger.valueOf(1), new BigInteger(dataStore.ceiling(createKey(0))));
}
@Test
public void testLastAdd() {
IDataMap<Long> map = dataStore.getMap("".getBytes(), LongKeyType.instance);
long last = 0;
for (int i = 0; i < 10; i++) {
Long lastLongValue = map.last();
if (lastLongValue == null) {
last = -1;
} else {
last = lastLongValue;
}
map.add(lastLongValue == null ? LongKeyType.instance.nullKey() : LongKeyType.instance.next(lastLongValue));
Assert.assertTrue(last < map.last());
}
}
@Test
public void testAdd() {
writePattern();
IDataMap<Long> map = dataStore.getMap("".getBytes(), LongKeyType.instance);
long last = -1;
for (int i = 0; i < 100; i++) {
Long value = map.add();
Assert.assertTrue(last < value);
last = value;
}
}
@Test
public void testAddWithRemoves() {
IDataMap<Long> map = dataStore.getMap("".getBytes(), LongKeyType.instance);
for (int i = 0; i < 100; i++) {
Long value = map.add();
dataStore.delete(map.getStoreKey(value));
}
}
private byte[] createKey(int key) {
return BigInteger.valueOf(key).toByteArray();
}
}