package org.openrdf.store.blob;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
public abstract class BlobStoreTestCase extends TestCase {
protected BlobStore store;
protected File dir;
protected AssertionFailedError error;
public abstract BlobStore createBlobStore(File dir) throws IOException;
public void setUp() throws Exception {
String tmpDirStr = System.getProperty("java.io.tmpdir");
if (tmpDirStr != null) {
File tmpDir = new File(tmpDirStr);
if (!tmpDir.exists()) {
tmpDir.mkdirs();
}
}
dir = File.createTempFile("store", "");
dir.delete();
dir.mkdirs();
store = createBlobStore(dir);
error = null;
}
public void tearDown() throws Exception {
store.erase();
dir.delete();
}
public void testEraseEmpty() throws Exception {
store.erase();
assertEmpty(dir);
}
public void testEraseSingleBlob() throws Exception {
BlobVersion trx1 = store.newVersion("urn:test:trx1");
Writer file = trx1.open("urn:test:file").openWriter();
file.append("blob store test");
file.close();
trx1.commit();
store.erase();
assertEmpty(dir);
}
public void testEraseMultiVersionSingleBlob() throws Exception {
Writer file = store.open("urn:test:file").openWriter();
file.append("blob store test1");
file.close();
file = store.open("urn:test:file").openWriter();
file.append("blob store test2");
file.close();
store.erase();
assertEmpty(dir);
}
public void testRoundTripString() throws Exception {
BlobVersion trx1 = store.newVersion("urn:test:trx1");
Writer file = trx1.open("urn:test:file").openWriter();
file.append("blob store test");
file.close();
trx1.commit();
BlobVersion trx2 = store.newVersion("urn:test:trx2");
CharSequence str = trx2.open("urn:test:file").getCharContent(true);
assertEquals("blob store test", str.toString());
}
public void testReuseVersion() throws Exception {
BlobVersion trx1 = store.newVersion("urn:test:trx1");
Writer file1 = trx1.open("urn:test:file1").openWriter();
file1.append("blob store test");
file1.close();
trx1.commit();
BlobVersion trx2 = store.newVersion("urn:test:trx2");
file1 = trx2.open("urn:test:file1").openWriter();
file1.append("blob store test");
file1.close();
trx2.commit();
Writer file2 = trx2.open("urn:test:file2").openWriter();
file2.append("blob store test");
file2.close();
trx2.commit();
trx2 = store.newVersion("urn:test:trx2");
file2 = trx2.open("urn:test:file2").openWriter();
file2.append("blob store test");
file2.close();
trx2.commit();
BlobVersion trx3 = store.newVersion("urn:test:trx3");
CharSequence str1 = trx3.open("urn:test:file1").getCharContent(true);
assertEquals("blob store test", str1.toString());
CharSequence str2 = trx3.open("urn:test:file2").getCharContent(true);
assertEquals("blob store test", str2.toString());
}
public void testReuseVersionWithDelete() throws Exception {
BlobVersion trx1 = store.newVersion("urn:test:trx1");
Writer file1 = trx1.open("urn:test:file1").openWriter();
file1.append("blob store test");
file1.close();
trx1.commit();
BlobVersion trx2 = store.newVersion("urn:test:trx2");
trx2.open("urn:test:file1").delete();
trx2.commit();
trx2 = store.newVersion("urn:test:trx2");
Writer file2 = trx2.open("urn:test:file2").openWriter();
file2.append("blob store test");
file2.close();
trx2.commit();
trx2 = store.newVersion("urn:test:trx2");
trx2.open("urn:test:file2").delete();
trx2.commit();
BlobVersion trx3 = store.newVersion("urn:test:trx3");
CharSequence str1 = trx3.open("urn:test:file1").getCharContent(true);
assertNull(str1);
CharSequence str2 = trx3.open("urn:test:file2").getCharContent(true);
assertNull(str2);
}
public void testAutocommit() throws Exception {
Writer file = store.open("urn:test:file").openWriter();
file.append("blob store test");
file.close();
CharSequence str = store.open("urn:test:file").getCharContent(true);
assertEquals("blob store test", str.toString());
}
public void testConcurrency() throws Exception {
Writer test1 = store.open("urn:test:file").openWriter();
test1.append("test1");
test1.close();
Writer test2 = store.open("urn:test:file").openWriter();
test2.append("test2");
test2.flush();
assertEquals("test1", store.open("urn:test:file").getCharContent(true).toString());
test2.close();
assertEquals("test2", store.open("urn:test:file").getCharContent(true).toString());
}
public void testReopenInvalid() throws Exception {
try {
store.openVersion("urn:test:nothing");
fail();
} catch (IllegalArgumentException e) {
// pass
}
}
public void testAtomicity() throws Exception {
BlobVersion trx1 = store.newVersion("urn:test:trx1");
Writer file1 = trx1.open("urn:test:file1").openWriter();
file1.append("blob store test");
file1.close();
Writer file2 = trx1.open("urn:test:file2").openWriter();
file2.append("blob store test");
file2.close();
BlobVersion trx2 = store.newVersion("urn:test:trx2");
assertNull(trx2.open("urn:test:file1").getCharContent(true));
assertNull(trx2.open("urn:test:file2").getCharContent(true));
trx1.commit();
BlobVersion trx3 = store.newVersion("urn:test:trx3");
assertEquals("blob store test", trx3.open("urn:test:file1")
.getCharContent(true).toString());
assertEquals("blob store test", trx3.open("urn:test:file2")
.getCharContent(true).toString());
}
public void testIsolation() throws Exception {
BlobVersion trx1 = store.newVersion("urn:test:trx1");
Writer file1 = trx1.open("urn:test:file1").openWriter();
file1.append("blob store test");
file1.close();
final CountDownLatch latch1 = new CountDownLatch(1);
new Thread(new Runnable() {
public void run() {
try {
error = null;
try {
BlobVersion trx2 = store.newVersion("urn:test:trx2");
BlobObject blob = trx2.open("urn:test:file1");
assertNull(blob.getCharContent(true));
} catch (Exception e) {
e.printStackTrace();
fail();
} finally {
latch1.countDown();
}
} catch (AssertionFailedError e) {
error = e;
}
}
}).start();
latch1.await();
if (error != null)
throw error;
trx1.prepare();
final CountDownLatch latch2 = new CountDownLatch(1);
final CountDownLatch latch3 = new CountDownLatch(1);
new Thread(new Runnable() {
public void run() {
try {
error = null;
try {
latch2.countDown();
BlobVersion trx3 = store.newVersion("urn:test:trx3");
BlobObject blob = trx3.open("urn:test:file1");
CharSequence str = blob.getCharContent(true);
assertNotNull(str);
assertEquals("blob store test", str.toString());
} catch (Exception e) {
e.printStackTrace();
fail();
} finally {
latch3.countDown();
}
} catch (AssertionFailedError e) {
error = e;
}
}
}).start();
latch2.await();
assertFalse(latch3.await(1, TimeUnit.SECONDS));
trx1.commit();
latch3.await();
if (error != null)
throw error;
}
protected void assertEmpty(File dir) {
assertEquals(dir.getName() + "/", tree(dir, 0).toString());
}
private CharSequence tree(File dir, int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
sb.append(dir.getName());
if (dir.isDirectory()) {
sb.append("/");
for (File file : dir.listFiles()) {
sb.append("\n").append(tree(file, depth + 1));
}
}
return sb;
}
}