package org.jboss.cache.loader;
import com.sleepycat.je.*;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jboss.cache.Fqn;
import org.jboss.cache.Modification;
import org.jboss.cache.TreeCache;
import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;
import java.util.*;
/**
* Tests BdbjeCacheLoader directly via the CacheLoader interface.
*
* <p>Run this test case with the current directory set to the JE environment
* directory. Any scratch directory will do, but beware that all files in
* the directory will be deleted by setUp().</p>
*
* @version $Revision: 1054 $
*/
public class BdbjeTest extends TestCase {
private static final String envHome = ".";
private static final Fqn FQN = new Fqn("key");
private TreeCache treeCache;
private CacheLoader loader;
/**
* Creates a test case.
*/
public BdbjeTest(String name) {
super(name);
}
/**
* Deletes all files in the environment directory.
*/
public void setUp() throws Exception {
super.setUp();
File dir = new File(envHome);
class MyFilter implements FileFilter {
public boolean accept(File file) {
return file.getName().endsWith(".jdb");
}
}
File[] files=dir.listFiles(new MyFilter());
if (files != null) {
for (int i = 0; i < files.length; i += 1) {
File file = files[i];
if (file.isFile()) {
if (!file.delete()) {
System.err.println("Unable to delete: " + file);
}
}
}
}
}
/**
* Release all resources and ignore exceptions, to shutdown gracefully
* when an assertion fires.
*/
public void tearDown() throws Exception {
super.tearDown();
if (loader != null) {
try {
loader.stop();
} catch (Exception ignored) {}
loader = null;
}
if (treeCache != null) {
try {
treeCache.stopService();
} catch (Exception ignored) {}
treeCache = null;
}
}
/**
* Creates and starts a loader.
* @param transactional whether to set the TransactionManagerLookupClass
* property.
* @param dbName a database name, or null to default to the cluster name.
*/
private void startLoader(boolean transactional, String dbName)
throws Exception {
/*
* Create a dummy TreeCache object. This is used for setting the cluster
* name and TransactionManagerLookupClass (transactional) propertes only.
* the TreeCache object is not used otherwise during testing.
*/
treeCache = new TreeCache();
treeCache.setClusterName("myCluster");
if (transactional) {
treeCache.setTransactionManagerLookupClass(
"org.jboss.cache.DummyTransactionManagerLookup");
}
treeCache.startService();
/* Derive the config string. */
String configStr;
if (dbName != null) {
configStr = envHome + '#' + dbName;
} else {
configStr = envHome;
dbName = "myCluster";
}
instantiateLoader();
/* Initialize and start the loader. */
loader.setCache(treeCache);
Properties props=new Properties();
props.setProperty("location", configStr);
loader.setConfig(props);
loader.create();
loader.start();
/* Verify the database name by trying to open it. */
Environment env = new Environment(new File(envHome), null);
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(transactional);
Database db = env.openDatabase(null, dbName, dbConfig);
db.close();
env.close();
}
/**
* Creates the loader instance.
*/
private void instantiateLoader()
throws Exception {
/* Create the cache loader as TreeCache would. */
Class cls =
Class.forName("org.jboss.cache.loader.bdbje.BdbjeCacheLoader");
loader = (CacheLoader) cls.newInstance();
}
/**
* Stops and destroys the loader.
*/
private void stopLoader()
throws Exception {
loader.stop();
loader.destroy();
}
/**
* Tests basic operations without a transaction.
*/
public void testBasicOperations()
throws Exception {
doTestBasicOperations(false);
}
/**
* Tests basic operations with a transaction.
*/
public void testBasicOperationsTransactional()
throws Exception {
doTestBasicOperations(true);
}
/**
* Tests basic operations.
*/
private void doTestBasicOperations(boolean transactional)
throws Exception {
startLoader(transactional, null);
/* One FQN only. */
doPutTests(new Fqn("key"));
doRemoveTests(new Fqn("key"));
assertEquals(0, loader.loadEntireState().length);
/* Add three FQNs, middle FQN last. */
doPutTests(new Fqn("key1"));
doPutTests(new Fqn("key3"));
doPutTests(new Fqn("key2"));
assertEquals(4, loader.get(new Fqn("key1")).size());
assertEquals(4, loader.get(new Fqn("key2")).size());
assertEquals(4, loader.get(new Fqn("key3")).size());
/* Remove middle FQN first, then the others. */
doRemoveTests(new Fqn("key2"));
doRemoveTests(new Fqn("key3"));
doRemoveTests(new Fqn("key1"));
assertEquals(null, loader.get(new Fqn("key1")));
assertEquals(null, loader.get(new Fqn("key2")));
assertEquals(null, loader.get(new Fqn("key3")));
assertEquals(0, loader.loadEntireState().length);
stopLoader();
}
/**
* Do basic put tests for a given FQN.
*/
private void doPutTests(Fqn fqn)
throws Exception {
assertTrue(!loader.exists(fqn));
/* put(Fqn,Object,Object) and get(Fqn,Object) */
Object oldVal;
oldVal = loader.put(fqn, "one", "two");
assertNull(oldVal);
oldVal = loader.put(fqn, "three", "four");
assertNull(oldVal);
assertEquals("two", loader.get(fqn).get("one"));
assertEquals("four", loader.get(fqn).get("three"));
oldVal = loader.put(fqn, "one", "xxx");
assertEquals("two", oldVal);
oldVal = loader.put(fqn, "one", "two");
assertEquals("xxx", oldVal);
/* get(Fqn) */
Map map = loader.get(fqn);
assertEquals(2, map.size());
assertEquals("two", map.get("one"));
assertEquals("four", map.get("three"));
/* put(Fqn,Map) */
map.put("five", "six");
map.put("seven", "eight");
loader.put(fqn, map);
assertEquals("six", loader.get(fqn).get("five"));
assertEquals("eight", loader.get(fqn).get("seven"));
assertEquals(map, loader.get(fqn));
assertEquals(4, map.size());
assertTrue(loader.exists(fqn));
}
/**
* Do basic remove tests for a given FQN.
*/
private void doRemoveTests(Fqn fqn)
throws Exception {
/* remove(Fqn,Object) */
Object oldVal;
oldVal = loader.remove(fqn, "one");
assertEquals("two", oldVal);
oldVal = loader.remove(fqn, "five");
assertEquals("six", oldVal);
assertEquals(null, loader.get(fqn).get("one"));
assertEquals(null, loader.get(fqn).get("five"));
assertEquals("four", loader.get(fqn).get("three"));
assertEquals("eight", loader.get(fqn).get("seven"));
Map map = loader.get(fqn);
assertEquals(2, map.size());
assertEquals("four", map.get("three"));
assertEquals("eight", map.get("seven"));
/* remove(Fqn) */
assertTrue(loader.exists(fqn));
loader.remove(fqn);
assertNull("Null expected", loader.get(fqn));
assertTrue(!loader.exists(fqn));
}
/**
* Tests creating implicit intermediate nodes when a leaf node is created,
* and tests removing subtrees.
*/
public void testMultiLevelTree()
throws Exception {
startLoader(false, null);
/* Create top level node implicitly. */
assertTrue(!loader.exists(new Fqn("key0")));
loader.put(Fqn.fromString("/key0/level1/level2"), null);
assertTrue(loader.exists(Fqn.fromString("/key0/level1/level2")));
assertTrue(loader.exists(Fqn.fromString("/key0/level1")));
assertTrue(loader.exists(new Fqn("key0")));
/* Remove leaf, leaving implicitly created middle level. */
loader.put(Fqn.fromString("/key0/x/y"), null);
assertTrue(loader.exists(Fqn.fromString("/key0/x/y")));
assertTrue(loader.exists(Fqn.fromString("/key0/x")));
loader.remove(Fqn.fromString("/key0/x/y"));
assertTrue(!loader.exists(Fqn.fromString("/key0/x/y")));
assertTrue(loader.exists(Fqn.fromString("/key0/x")));
/* Delete top level to delete everything. */
loader.remove(new Fqn("key0"));
assertTrue(!loader.exists(new Fqn("key0")));
assertTrue(!loader.exists(Fqn.fromString("/key0/level1/level2")));
assertTrue(!loader.exists(Fqn.fromString("/key0/level1")));
assertTrue(!loader.exists(Fqn.fromString("/key0/x")));
/* Add three top level nodes as context. */
loader.put(new Fqn("key1"), null);
loader.put(new Fqn("key2"), null);
loader.put(new Fqn("key3"), null);
assertTrue(loader.exists(new Fqn("key1")));
assertTrue(loader.exists(new Fqn("key2")));
assertTrue(loader.exists(new Fqn("key3")));
/* Put /key3/level1/level2. level1 should be implicitly created. */
assertTrue(!loader.exists(Fqn.fromString("/key3/level1")));
assertTrue(!loader.exists(Fqn.fromString("/key3/level1/level2")));
loader.put(Fqn.fromString("/key3/level1/level2"), null);
assertTrue(loader.exists(Fqn.fromString("/key3/level1/level2")));
assertTrue(loader.exists(Fqn.fromString("/key3/level1")));
/* Context nodes should still be intact. */
assertTrue(loader.exists(new Fqn("key1")));
assertTrue(loader.exists(new Fqn("key2")));
assertTrue(loader.exists(new Fqn("key3")));
/* Remove middle level only. */
loader.remove(Fqn.fromString("/key3/level1"));
assertTrue(!loader.exists(Fqn.fromString("/key3/level1/level2")));
assertTrue(!loader.exists(Fqn.fromString("/key3/level1")));
/* Context nodes should still be intact. */
assertTrue(loader.exists(new Fqn("key1")));
assertTrue(loader.exists(new Fqn("key2")));
assertTrue(loader.exists(new Fqn("key3")));
/* Delete first root, leaving other roots. */
loader.remove(new Fqn("key1"));
assertTrue(!loader.exists(new Fqn("key1")));
assertTrue(loader.exists(new Fqn("key2")));
assertTrue(loader.exists(new Fqn("key3")));
/* Delete last root, leaving other roots. */
loader.remove(new Fqn("key3"));
assertTrue(loader.exists(new Fqn("key2")));
assertTrue(!loader.exists(new Fqn("key3")));
/* Delete final root, leaving none. */
loader.remove(new Fqn("key2"));
assertTrue(!loader.exists(new Fqn("key0")));
assertTrue(!loader.exists(new Fqn("key1")));
assertTrue(!loader.exists(new Fqn("key2")));
assertTrue(!loader.exists(new Fqn("key3")));
/* Repeat all tests above using put(Fqn,Object,Object) and get(Fqn) */
assertNull(loader.get(new Fqn("key0")));
loader.put(Fqn.fromString("/key0/level1/level2"), "a", "b");
assertNotNull(loader.get(Fqn.fromString("/key0/level1/level2")));
assertNotNull(loader.get(Fqn.fromString("/key0/level1")));
assertNotNull(loader.get(new Fqn("key0")));
assertEquals(0, loader.get(Fqn.fromString("/key0/level1")).size());
assertEquals(0, loader.get(new Fqn("key0")).size());
loader.put(Fqn.fromString("/key0/x/y"), "a", "b");
assertNotNull(loader.get(Fqn.fromString("/key0/x/y")));
assertNotNull(loader.get(Fqn.fromString("/key0/x")));
assertEquals(0, loader.get(Fqn.fromString("/key0/x")).size());
loader.remove(Fqn.fromString("/key0/x/y"));
assertNull(loader.get(Fqn.fromString("/key0/x/y")));
assertNotNull(loader.get(Fqn.fromString("/key0/x")));
assertEquals(0, loader.get(Fqn.fromString("/key0/x")).size());
loader.remove(new Fqn("key0"));
assertNull(loader.get(new Fqn("key0")));
assertNull(loader.get(Fqn.fromString("/key0/level1/level2")));
assertNull(loader.get(Fqn.fromString("/key0/level1")));
assertNull(loader.get(Fqn.fromString("/key0/x")));
loader.put(new Fqn("key1"), "a", "b");
loader.put(new Fqn("key2"), "a", "b");
loader.put(new Fqn("key3"), "a", "b");
assertNotNull(loader.get(new Fqn("key1")));
assertNotNull(loader.get(new Fqn("key2")));
assertNotNull(loader.get(new Fqn("key3")));
assertNull(loader.get(Fqn.fromString("/key3/level1")));
assertNull(loader.get(Fqn.fromString("/key3/level1/level2")));
loader.put(Fqn.fromString("/key3/level1/level2"), "a", "b");
assertNotNull(loader.get(Fqn.fromString("/key3/level1/level2")));
assertNotNull(loader.get(Fqn.fromString("/key3/level1")));
assertEquals(0, loader.get(Fqn.fromString("/key3/level1")).size());
assertNotNull(loader.get(new Fqn("key1")));
assertNotNull(loader.get(new Fqn("key2")));
assertNotNull(loader.get(new Fqn("key3")));
loader.remove(Fqn.fromString("/key3/level1"));
assertNull(loader.get(Fqn.fromString("/key3/level1/level2")));
assertNull(loader.get(Fqn.fromString("/key3/level1")));
assertNotNull(loader.get(new Fqn("key1")));
assertNotNull(loader.get(new Fqn("key2")));
assertNotNull(loader.get(new Fqn("key3")));
loader.remove(new Fqn("key1"));
assertNull(loader.get(new Fqn("key1")));
assertNotNull(loader.get(new Fqn("key2")));
assertNotNull(loader.get(new Fqn("key3")));
loader.remove(new Fqn("key3"));
assertNotNull(loader.get(new Fqn("key2")));
assertNull(loader.get(new Fqn("key3")));
loader.remove(new Fqn("key2"));
assertNull(loader.get(new Fqn("key0")));
assertNull(loader.get(new Fqn("key1")));
assertNull(loader.get(new Fqn("key2")));
assertNull(loader.get(new Fqn("key3")));
stopLoader();
}
/**
* Tests the getChildrenNames() method.
*/
public void testGetChildrenNames()
throws Exception {
startLoader(false, null);
checkChildren(new Fqn(), null);
checkChildren(Fqn.fromString("/key0"), null);
loader.put(Fqn.fromString("/key0"), null);
checkChildren(new Fqn(), new String[] { "key0" });
loader.put(Fqn.fromString("/key1/x"), null);
checkChildren(new Fqn(), new String[] { "key0", "key1" });
checkChildren(Fqn.fromString("/key1"), new String[] { "x" });
loader.remove(Fqn.fromString("/key1/x"));
checkChildren(new Fqn(), new String[] { "key0", "key1" });
checkChildren(Fqn.fromString("/key0"), null);
checkChildren(Fqn.fromString("/key1"), null);
loader.put(Fqn.fromString("/key0/a"), null);
loader.put(Fqn.fromString("/key0/ab"), null);
loader.put(Fqn.fromString("/key0/abc"), null);
checkChildren(Fqn.fromString("/key0"),
new String[] { "a", "ab", "abc" });
loader.put(Fqn.fromString("/key0/xxx"), null);
loader.put(Fqn.fromString("/key0/xx"), null);
loader.put(Fqn.fromString("/key0/x"), null);
checkChildren(Fqn.fromString("/key0"),
new String[] { "a", "ab", "abc", "x", "xx", "xxx" });
loader.put(Fqn.fromString("/key0/a/1"), null);
loader.put(Fqn.fromString("/key0/a/2"), null);
loader.put(Fqn.fromString("/key0/a/2/1"), null);
checkChildren(Fqn.fromString("/key0/a/2"), new String[] { "1" });
checkChildren(Fqn.fromString("/key0/a"), new String[] { "1", "2" });
checkChildren(Fqn.fromString("/key0"),
new String[] { "a", "ab", "abc", "x", "xx", "xxx" });
loader.put(Fqn.fromString("/key0/\u0000"), null);
loader.put(Fqn.fromString("/key0/\u0001"), null);
checkChildren(Fqn.fromString("/key0"),
new String[] { "a", "ab", "abc", "x", "xx", "xxx",
"\u0000", "\u0001"});
loader.put(Fqn.fromString("/\u0001"), null);
checkChildren(new Fqn(), new String[] { "key0", "key1", "\u0001" });
loader.put(Fqn.fromString("/\u0001/\u0001"), null);
checkChildren(Fqn.fromString("/\u0001"), new String[] { "\u0001" });
loader.put(Fqn.fromString("/\u0001/\uFFFF"), null);
checkChildren(Fqn.fromString("/\u0001"),
new String[] { "\u0001", "\uFFFF" });
loader.put(Fqn.fromString("/\u0001/\uFFFF/\u0001"), null);
checkChildren(Fqn.fromString("/\u0001/\uFFFF"),
new String[] { "\u0001" });
stopLoader();
}
/**
* Checks that the given list of children part names is returned.
*/
private void checkChildren(Fqn fqn, String[] names)
throws Exception {
Set set = loader.getChildrenNames(fqn);
if (names != null) {
assertEquals(names.length, set.size());
for (int i = 0; i < names.length; i += 1) {
assertTrue(set.contains(names[i]));
}
} else {
assertNull(set);
}
}
/**
* Tests basic operations without a transaction.
*/
public void testModifications()
throws Exception {
doTestModifications(false);
}
/**
* Tests basic operations with a transaction.
*/
public void testModificationsTransactional()
throws Exception {
doTestModifications(true);
}
/**
* Tests modifications.
*/
private void doTestModifications(boolean transactional)
throws Exception {
startLoader(transactional, null);
/* PUT_KEY_VALUE, PUT_DATA */
List list = createUpdates();
loader.put(list);
checkModifications(list);
/* REMOVE_KEY_VALUE */
list = new ArrayList();
Modification mod = new Modification();
mod.setType(Modification.REMOVE_KEY_VALUE);
mod.setFqn(FQN);
mod.setKey("one");
list.add(mod);
loader.put(list);
checkModifications(list);
/* REMOVE_NODE */
list = new ArrayList();
mod = new Modification();
mod.setType(Modification.REMOVE_NODE);
mod.setFqn(FQN);
list.add(mod);
loader.put(list);
checkModifications(list);
assertEquals(null, loader.get(FQN));
/* REMOVE_DATA */
loader.put(FQN, "one", "two");
list = new ArrayList();
mod = new Modification();
mod.setType(Modification.REMOVE_DATA);
mod.setFqn(FQN);
list.add(mod);
loader.put(list);
checkModifications(list);
assertNotNull(loader.get(FQN));
assertEquals(0, loader.get(FQN).size());
stopLoader();
}
/**
* Tests a one-phase transaction.
*/
public void testOnePhaseTransaction()
throws Exception {
startLoader(true, null);
List mods = createUpdates();
loader.prepare(null, mods, true);
checkModifications(mods);
stopLoader();
}
/**
* Tests a two-phase transaction.
*/
public void testTwoPhaseTransaction()
throws Exception {
startLoader(true, null);
Object txnKey = new Object();
List mods = createUpdates();
loader.prepare(txnKey, mods, false);
try {
checkModifications(mods);
fail("Expected lock timeout");
} catch (DeadlockException expected) {}
loader.commit(txnKey);
checkModifications(mods);
stopLoader();
}
/**
* Tests rollback of a two-phase transaction.
*/
public void testTransactionRollback()
throws Exception {
startLoader(true, null);
Object txnKey = new Object();
List mods = createUpdates();
loader.prepare(txnKey, mods, false);
loader.rollback(txnKey);
assertEquals(0, loader.loadEntireState().length);
stopLoader();
}
/**
* Creates a set of update (PUT_KEY_VALUE, PUT_DATA) modifications.
*/
private List createUpdates() {
List list = new ArrayList();
Modification mod = new Modification();
mod.setType(Modification.PUT_KEY_VALUE);
mod.setFqn(FQN);
mod.setKey("one");
mod.setValue("two");
list.add(mod);
mod = new Modification();
mod.setType(Modification.PUT_KEY_VALUE);
mod.setFqn(FQN);
mod.setKey("three");
mod.setValue("four");
list.add(mod);
Map map = new HashMap();
map.put("five", "six");
map.put("seven", "eight");
mod = new Modification();
mod.setType(Modification.PUT_DATA);
mod.setFqn(FQN);
mod.setData(map);
list.add(mod);
return list;
}
/**
* Checks that a list of modifications was applied.
*/
private void checkModifications(List list)
throws Exception {
for (int i = 0; i < list.size(); i += 1) {
Modification mod = (Modification) list.get(i);
Fqn fqn = mod.getFqn();
switch (mod.getType()) {
case Modification.PUT_KEY_VALUE:
assertEquals(mod.getValue(), loader.get(fqn).get(mod.getKey()));
break;
case Modification.PUT_DATA:
Map map = mod.getData();
for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
Object key = iter.next();
assertEquals(map.get(key), loader.get(fqn).get(key));
}
break;
case Modification.REMOVE_KEY_VALUE:
assertEquals(null, loader.get(fqn).get(mod.getKey()));
break;
case Modification.REMOVE_DATA:
assertTrue(loader.exists(fqn));
assertNotNull(loader.get(fqn));
assertEquals(0, loader.get(fqn).size());
break;
case Modification.REMOVE_NODE:
assertTrue(!loader.exists(fqn));
assertEquals(null, loader.get(fqn));
break;
default:
fail("unknown type: " + mod);
break;
}
}
}
/**
* Test exception cases and create/destroy/create/destroy sequence.
*/
// public void testBasicExceptions()
// throws Exception {
//
// instantiateLoader();
// checkPreCreateExceptions();
//
// startLoader(false, null);
// checkPostCreateExceptions();
// loader.put(FQN, "one", "two");
// assertEquals("two", loader.get(FQN).get("one"));
//
// stopLoader();
// checkPreCreateExceptions();
//
// startLoader(false, null);
// checkPostCreateExceptions();
// loader.put(FQN, "one", "two");
// assertEquals("two", loader.get(FQN).get("one"));
//
// stopLoader();
// checkPreCreateExceptions();
// }
/**
* Check exception cases that occur before create().
*/
private void checkPreCreateExceptions()
throws Exception {
loader.setCache(new TreeCache());
loader.setConfig(null);
try {
loader.start();
// fail();
} catch (IllegalStateException expected) {}
// loader.setCache(null);
Properties props=new Properties();
props.setProperty("location", "xyz");
loader.setConfig(props);
try {
loader.start();
fail();
} catch (IllegalStateException expected) {}
loader.setCache(new TreeCache());
props=new Properties();
props.setProperty("location", "directory_that_does_not_exist");
loader.setConfig(props);
try {
loader.start();
fail();
} catch (DatabaseException expected) {}
try {
loader.put(FQN, "one", "two");
fail();
} catch (IllegalStateException expected) {}
try {
loader.put(FQN, new HashMap());
fail();
} catch (IllegalStateException expected) {}
try {
loader.put(new ArrayList());
fail();
} catch (IllegalStateException expected) {}
try {
loader.get(FQN).get("one");
fail();
} catch (IllegalStateException expected) {}
try {
loader.get(FQN);
fail();
} catch (IllegalStateException expected) {}
try {
loader.remove(FQN);
fail();
} catch (IllegalStateException expected) {}
try {
loader.remove(FQN, "one");
fail();
} catch (IllegalStateException expected) {}
try {
loader.prepare(new Object(), new ArrayList(), false);
fail();
} catch (IllegalStateException expected) {}
try {
loader.commit(new Object());
fail();
} catch (IllegalStateException expected) {}
try {
loader.rollback(new Object());
fail();
} catch (IllegalStateException expected) {}
try {
loader.loadEntireState();
fail();
} catch (IllegalStateException expected) {}
try {
loader.storeEntireState(new byte[0]);
fail();
} catch (IllegalStateException expected) {}
/* Redundant stop and destroy are allowed. */
loader.stop();
loader.destroy();
}
/**
* Check exception cases that occur after create().
*/
private void checkPostCreateExceptions()
throws Exception {
try {
loader.create();
fail();
} catch (IllegalStateException expected) {}
try {
loader.start();
fail();
} catch (IllegalStateException expected) {}
try {
loader.put(null, "one", "two");
fail();
} catch (NullPointerException expected) {}
try {
loader.put(null, new HashMap());
fail();
} catch (NullPointerException expected) {}
try {
loader.put(null);
fail();
} catch (NullPointerException expected) {}
try {
loader.get(null).get("one");
fail();
} catch (NullPointerException expected) {}
try {
loader.get(null);
fail();
} catch (NullPointerException expected) {}
try {
loader.remove(null);
fail();
} catch (NullPointerException expected) {}
try {
loader.remove(null, "one");
fail();
} catch (NullPointerException expected) {}
try {
loader.prepare(null, new ArrayList(), false);
fail();
} catch (NullPointerException expected) {}
try {
loader.prepare(new Object(), null, false);
fail();
} catch (NullPointerException expected) {}
try {
loader.commit(null);
fail();
} catch (NullPointerException expected) {}
try {
loader.rollback(null);
fail();
} catch (NullPointerException expected) {}
}
/**
* Tests a non-transactional prepare.
*/
public void testTransactionExceptions()
throws Exception {
List mods = createUpdates();
/* A non-transactional cache loader should not allow prepare(). */
startLoader(false, null);
try {
loader.prepare(new Object(), mods, false);
fail();
} catch (UnsupportedOperationException expected) {}
stopLoader();
startLoader(true, null);
/* Commit and rollback a non-prepared transaction. */
try {
loader.commit(new Object());
fail();
} catch (IllegalArgumentException expected) {}
try {
loader.rollback(new Object());
fail();
} catch (IllegalArgumentException expected) {}
/* Commit and rollback after commit. */
loader.storeEntireState(null);
Object txnKey = new Object();
loader.prepare(txnKey, mods, false);
loader.commit(txnKey);
try {
loader.commit(txnKey);
fail();
} catch (IllegalArgumentException expected) {}
try {
loader.rollback(txnKey);
fail();
} catch (IllegalArgumentException expected) {}
/* Commit and rollback after rollback. */
loader.storeEntireState(null);
txnKey = new Object();
loader.prepare(txnKey, mods, false);
loader.rollback(txnKey);
try {
loader.rollback(txnKey);
fail();
} catch (IllegalArgumentException expected) {}
try {
loader.rollback(txnKey);
fail();
} catch (IllegalArgumentException expected) {}
stopLoader();
}
/**
* Tests that null keys and values work as for a standard Java Map.
*/
public void testNullKeysAndValues()
throws Exception {
startLoader(false, null);
loader.put(FQN, null, "x");
assertEquals("x", loader.get(FQN).get(null));
Map map = loader.get(FQN);
assertEquals(1, map.size());
assertEquals("x", map.get(null));
loader.put(FQN, "y", null);
assertEquals(null, loader.get(FQN).get("y"));
map = loader.get(FQN);
assertEquals(2, map.size());
assertEquals("x", map.get(null));
assertEquals(null, map.get("y"));
loader.remove(FQN, null);
assertEquals(null, loader.get(FQN).get(null));
assertEquals(1, loader.get(FQN).size());
loader.remove(FQN, "y");
assertNotNull(loader.get(FQN));
assertEquals(0, loader.get(FQN).size());
map = new HashMap();
map.put(null, null);
loader.put(FQN, map);
assertEquals(map, loader.get(FQN));
loader.remove(FQN);
assertNull("Should be null", loader.get(FQN));
map = new HashMap();
map.put("xyz", null);
map.put(null, "abc");
loader.put(FQN, map);
assertEquals(map, loader.get(FQN));
loader.remove(FQN);
assertEquals(null, loader.get(FQN));
stopLoader();
}
/**
* Test non-default database name.
*/
public void testDatabaseName()
throws Exception {
startLoader(false, "nonDefaultDbName");
loader.put(FQN, "one", "two");
assertEquals("two", loader.get(FQN).get("one"));
stopLoader();
}
/**
* Test load/store state.
*/
public void testLoadAndStore()
throws Exception {
startLoader(false, null);
/* Empty state. */
assertEquals(0, loader.loadEntireState().length);
loader.storeEntireState(new byte[0]);
assertEquals(0, loader.loadEntireState().length);
loader.storeEntireState(null);
assertEquals(0, loader.loadEntireState().length);
assertEquals(null, loader.get(FQN));
/* Use a complex object to ensure that the class catalog is used. */
Complex c1 = new Complex();
Complex c2 = new Complex(c1);
/* Add objects. */
loader.put(FQN, new Integer(1), c1);
loader.put(FQN, new Integer(2), c2);
assertEquals(c1, loader.get(FQN).get(new Integer(1)));
assertEquals(c2, loader.get(FQN).get(new Integer(2)));
assertEquals(2, loader.get(FQN).size());
/* Save state. */
byte[] state = loader.loadEntireState();
assertTrue(state.length > 0);
/* Clear state. */
loader.storeEntireState(null);
assertEquals(0, loader.loadEntireState().length);
assertEquals(null, loader.get(FQN));
/* Restore state. */
loader.storeEntireState(state);
assertEquals(c1, loader.get(FQN).get(new Integer(1)));
assertEquals(c2, loader.get(FQN).get(new Integer(2)));
assertEquals(2, loader.get(FQN).size());
stopLoader();
}
public static Test suite()
throws Exception {
return new TestSuite(BdbjeTest.class);
}
public static void main(String[] args)
throws Exception {
junit.textui.TestRunner.run(suite());
}
/**
* Complex object whose class description is stored in the class catalog.
*/
private static class Complex implements Serializable {
Complex nested;
Complex() {
this(null);
}
Complex(Complex nested) {
this.nested = nested;
}
public boolean equals(Object o) {
try {
Complex x = (Complex) o;
return (nested != null) ? nested.equals(x.nested)
: (x.nested == null);
} catch (ClassCastException e) {
return false;
}
}
}
}