Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 1,394   Methods: 34
NCLOC: 1,019   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
BdbjeTest.java 79.2% 81.6% 91.2% 82%
coverage coverage
 1    package org.jboss.cache.loader;
 2   
 3    import com.sleepycat.je.Database;
 4    import com.sleepycat.je.DatabaseConfig;
 5    import com.sleepycat.je.DatabaseException;
 6    import com.sleepycat.je.DeadlockException;
 7    import com.sleepycat.je.Environment;
 8    import junit.framework.Test;
 9    import junit.framework.TestCase;
 10    import junit.framework.TestSuite;
 11    import org.jboss.cache.CacheImpl;
 12    import org.jboss.cache.CacheSPI;
 13    import org.jboss.cache.DefaultCacheFactory;
 14    import org.jboss.cache.Fqn;
 15    import org.jboss.cache.Modification;
 16    import org.jboss.cache.loader.bdbje.BdbjeCacheLoaderConfig;
 17    import org.jboss.cache.statetransfer.StateTransferManager;
 18    import org.jboss.util.stream.MarshalledValueInputStream;
 19    import org.jboss.util.stream.MarshalledValueOutputStream;
 20   
 21    import java.io.ByteArrayInputStream;
 22    import java.io.ByteArrayOutputStream;
 23    import java.io.File;
 24    import java.io.FileFilter;
 25    import java.io.Serializable;
 26    import java.util.ArrayList;
 27    import java.util.HashMap;
 28    import java.util.List;
 29    import java.util.Map;
 30    import java.util.Set;
 31   
 32    /**
 33    * Tests BdbjeCacheLoader directly via the CacheLoader interface.
 34    * <p/>
 35    * <p>Run this test case with the current directory set to the JE environment
 36    * directory. Any scratch directory will do, but beware that all files in
 37    * the directory will be deleted by setUp().</p>
 38    *
 39    * @version $Revision: 1.21 $
 40    */
 41    public class BdbjeTest extends TestCase
 42    {
 43   
 44    private static final int STREAM_HEADER_LENGTH = 4;
 45    private static final String envHome = ".";
 46    private static final Fqn FQN = new Fqn("key");
 47   
 48    private CacheImpl cache;
 49    private CacheLoader loader;
 50   
 51    /**
 52    * Creates a test case.
 53    */
 54  13 public BdbjeTest(String name)
 55    {
 56  13 super(name);
 57    }
 58   
 59    /**
 60    * Deletes all files in the environment directory.
 61    */
 62  13 public void setUp() throws Exception
 63    {
 64  13 super.setUp();
 65   
 66  13 File dir = new File(envHome);
 67   
 68    class MyFilter implements FileFilter
 69    {
 70  455 public boolean accept(File file)
 71    {
 72  455 return file.getName().endsWith(".jdb");
 73    }
 74    }
 75   
 76  13 File[] files = dir.listFiles(new MyFilter());
 77   
 78  13 if (files != null)
 79    {
 80  13 for (int i = 0; i < files.length; i += 1)
 81    {
 82  13 File file = files[i];
 83  13 if (file.isFile())
 84    {
 85  13 if (!file.delete())
 86    {
 87  0 System.err.println("Unable to delete: " + file);
 88    }
 89    }
 90    }
 91    }
 92    }
 93   
 94    /**
 95    * Release all resources and ignore exceptions, to shutdown gracefully
 96    * when an assertion fires.
 97    */
 98  13 public void tearDown() throws Exception
 99    {
 100  13 super.tearDown();
 101   
 102  13 if (loader != null)
 103    {
 104  13 try
 105    {
 106  13 loader.stop();
 107    }
 108    catch (Exception ignored)
 109    {
 110    }
 111  13 loader = null;
 112    }
 113  13 if (cache != null)
 114    {
 115  13 try
 116    {
 117  13 cache.stop();
 118    }
 119    catch (Exception ignored)
 120    {
 121    }
 122  13 cache = null;
 123    }
 124    }
 125   
 126    /**
 127    * Creates and starts a loader.
 128    *
 129    * @param transactional whether to set the TransactionManagerLookupClass
 130    * property.
 131    * @param dbName a database name, or null to default to the cluster name.
 132    */
 133  14 private void startLoader(boolean transactional, String dbName)
 134    throws Exception
 135    {
 136   
 137    /*
 138    * Create a dummy CacheImpl object. This is used for setting the cluster
 139    * name and TransactionManagerLookupClass (transactional) propertes only.
 140    * the CacheImpl object is not used otherwise during testing.
 141    */
 142  14 cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(false);
 143  14 cache.getConfiguration().setClusterName("myCluster");
 144  14 if (transactional)
 145    {
 146  6 cache.getConfiguration().setTransactionManagerLookupClass(
 147    "org.jboss.cache.transaction.DummyTransactionManagerLookup");
 148    }
 149  14 cache.start();
 150   
 151    /* Derive the config string. */
 152  14 String configStr;
 153  14 if (dbName != null)
 154    {
 155  1 configStr = envHome + '#' + dbName;
 156    }
 157    else
 158    {
 159  13 configStr = envHome;
 160  13 dbName = "myCluster";
 161    }
 162   
 163  14 instantiateLoader();
 164   
 165    /* Initialize and start the loader. */
 166  14 loader.setCache(cache);
 167  14 BdbjeCacheLoaderConfig config = new BdbjeCacheLoaderConfig();
 168  14 config.setLocation(configStr);
 169  14 loader.setConfig(config);
 170  14 loader.create();
 171  14 loader.start();
 172   
 173    /* Verify the database name by trying to open it. */
 174  14 Environment env = new Environment(new File(envHome), null);
 175  14 DatabaseConfig dbConfig = new DatabaseConfig();
 176  14 dbConfig.setTransactional(transactional);
 177  14 Database db = env.openDatabase(null, dbName, dbConfig);
 178  14 db.close();
 179  14 env.close();
 180    }
 181   
 182    /**
 183    * Creates the loader instance.
 184    */
 185  14 private void instantiateLoader()
 186    throws Exception
 187    {
 188   
 189    /* Create the cache loader as CacheImpl would. */
 190  14 Class cls =
 191    Class.forName("org.jboss.cache.loader.bdbje.BdbjeCacheLoader");
 192  14 loader = (CacheLoader) cls.newInstance();
 193    }
 194   
 195    /**
 196    * Stops and destroys the loader.
 197    */
 198  14 private void stopLoader()
 199    throws Exception
 200    {
 201   
 202  14 loader.stop();
 203  14 loader.destroy();
 204    }
 205   
 206    /**
 207    * Tests basic operations without a transaction.
 208    */
 209  1 public void testBasicOperations()
 210    throws Exception
 211    {
 212   
 213  1 doTestBasicOperations(false);
 214    }
 215   
 216    /**
 217    * Tests basic operations with a transaction.
 218    */
 219  1 public void testBasicOperationsTransactional()
 220    throws Exception
 221    {
 222   
 223  1 doTestBasicOperations(true);
 224    }
 225   
 226    /**
 227    * Tests basic operations.
 228    */
 229  2 private void doTestBasicOperations(boolean transactional)
 230    throws Exception
 231    {
 232   
 233  2 startLoader(transactional, null);
 234   
 235    /* One FQN only. */
 236  2 doPutTests(new Fqn("key"));
 237  2 doRemoveTests(new Fqn("key"));
 238   
 239  2 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
 240  2 MarshalledValueOutputStream os = new MarshalledValueOutputStream(baos);
 241  2 loader.loadEntireState(os);
 242  2 os.close();
 243   
 244    /* Add three FQNs, middle FQN last. */
 245  2 doPutTests(new Fqn("key1"));
 246  2 doPutTests(new Fqn("key3"));
 247  2 doPutTests(new Fqn("key2"));
 248  2 assertEquals(4, loader.get(new Fqn("key1")).size());
 249  2 assertEquals(4, loader.get(new Fqn("key2")).size());
 250  2 assertEquals(4, loader.get(new Fqn("key3")).size());
 251   
 252    /* Remove middle FQN first, then the others. */
 253  2 doRemoveTests(new Fqn("key2"));
 254  2 doRemoveTests(new Fqn("key3"));
 255  2 doRemoveTests(new Fqn("key1"));
 256  2 assertEquals(null, loader.get(new Fqn("key1")));
 257  2 assertEquals(null, loader.get(new Fqn("key2")));
 258  2 assertEquals(null, loader.get(new Fqn("key3")));
 259   
 260  2 baos = new ByteArrayOutputStream(1024);
 261  2 os = new MarshalledValueOutputStream(baos);
 262  2 loader.loadEntireState(os);
 263  2 os.close();
 264   
 265  2 stopLoader();
 266    }
 267   
 268    /**
 269    * Do basic put tests for a given FQN.
 270    */
 271  8 private void doPutTests(Fqn fqn)
 272    throws Exception
 273    {
 274   
 275  8 assertTrue(!loader.exists(fqn));
 276   
 277    /* put(Fqn,Object,Object) and get(Fqn,Object) */
 278  8 Object oldVal;
 279  8 oldVal = loader.put(fqn, "one", "two");
 280  8 assertNull(oldVal);
 281  8 oldVal = loader.put(fqn, "three", "four");
 282  8 assertNull(oldVal);
 283  8 assertEquals("two", loader.get(fqn).get("one"));
 284  8 assertEquals("four", loader.get(fqn).get("three"));
 285  8 oldVal = loader.put(fqn, "one", "xxx");
 286  8 assertEquals("two", oldVal);
 287  8 oldVal = loader.put(fqn, "one", "two");
 288  8 assertEquals("xxx", oldVal);
 289   
 290    /* get(Fqn) */
 291  8 Map map = loader.get(fqn);
 292  8 assertEquals(2, map.size());
 293  8 assertEquals("two", map.get("one"));
 294  8 assertEquals("four", map.get("three"));
 295   
 296    /* put(Fqn,Map) */
 297  8 map.put("five", "six");
 298  8 map.put("seven", "eight");
 299  8 loader.put(fqn, map);
 300  8 assertEquals("six", loader.get(fqn).get("five"));
 301  8 assertEquals("eight", loader.get(fqn).get("seven"));
 302  8 assertEquals(map, loader.get(fqn));
 303  8 assertEquals(4, map.size());
 304   
 305  8 assertTrue(loader.exists(fqn));
 306    }
 307   
 308    /**
 309    * Do basic remove tests for a given FQN.
 310    */
 311  8 private void doRemoveTests(Fqn fqn)
 312    throws Exception
 313    {
 314   
 315    /* remove(Fqn,Object) */
 316  8 Object oldVal;
 317  8 oldVal = loader.remove(fqn, "one");
 318  8 assertEquals("two", oldVal);
 319  8 oldVal = loader.remove(fqn, "five");
 320  8 assertEquals("six", oldVal);
 321  8 assertEquals(null, loader.get(fqn).get("one"));
 322  8 assertEquals(null, loader.get(fqn).get("five"));
 323  8 assertEquals("four", loader.get(fqn).get("three"));
 324  8 assertEquals("eight", loader.get(fqn).get("seven"));
 325  8 Map map = loader.get(fqn);
 326  8 assertEquals(2, map.size());
 327  8 assertEquals("four", map.get("three"));
 328  8 assertEquals("eight", map.get("seven"));
 329   
 330    /* remove(Fqn) */
 331  8 assertTrue(loader.exists(fqn));
 332  8 loader.remove(fqn);
 333  8 assertNull("Null expected", loader.get(fqn));
 334  8 assertTrue(!loader.exists(fqn));
 335    }
 336   
 337    /**
 338    * Tests creating implicit intermediate nodes when a leaf node is created,
 339    * and tests removing subtrees.
 340    */
 341  1 public void testMultiLevelTree()
 342    throws Exception
 343    {
 344   
 345  1 startLoader(false, null);
 346   
 347    /* Create top level node implicitly. */
 348  1 assertTrue(!loader.exists(new Fqn("key0")));
 349  1 loader.put(Fqn.fromString("/key0/level1/level2"), null);
 350  1 assertTrue(loader.exists(Fqn.fromString("/key0/level1/level2")));
 351  1 assertTrue(loader.exists(Fqn.fromString("/key0/level1")));
 352  1 assertTrue(loader.exists(new Fqn("key0")));
 353   
 354    /* Remove leaf, leaving implicitly created middle level. */
 355  1 loader.put(Fqn.fromString("/key0/x/y"), null);
 356  1 assertTrue(loader.exists(Fqn.fromString("/key0/x/y")));
 357  1 assertTrue(loader.exists(Fqn.fromString("/key0/x")));
 358  1 loader.remove(Fqn.fromString("/key0/x/y"));
 359  1 assertTrue(!loader.exists(Fqn.fromString("/key0/x/y")));
 360  1 assertTrue(loader.exists(Fqn.fromString("/key0/x")));
 361   
 362    /* Delete top level to delete everything. */
 363  1 loader.remove(new Fqn("key0"));
 364  1 assertTrue(!loader.exists(new Fqn("key0")));
 365  1 assertTrue(!loader.exists(Fqn.fromString("/key0/level1/level2")));
 366  1 assertTrue(!loader.exists(Fqn.fromString("/key0/level1")));
 367  1 assertTrue(!loader.exists(Fqn.fromString("/key0/x")));
 368   
 369    /* Add three top level nodes as context. */
 370  1 loader.put(new Fqn("key1"), null);
 371  1 loader.put(new Fqn("key2"), null);
 372  1 loader.put(new Fqn("key3"), null);
 373  1 assertTrue(loader.exists(new Fqn("key1")));
 374  1 assertTrue(loader.exists(new Fqn("key2")));
 375  1 assertTrue(loader.exists(new Fqn("key3")));
 376   
 377    /* Put /key3/level1/level2. level1 should be implicitly created. */
 378  1 assertTrue(!loader.exists(Fqn.fromString("/key3/level1")));
 379  1 assertTrue(!loader.exists(Fqn.fromString("/key3/level1/level2")));
 380  1 loader.put(Fqn.fromString("/key3/level1/level2"), null);
 381  1 assertTrue(loader.exists(Fqn.fromString("/key3/level1/level2")));
 382  1 assertTrue(loader.exists(Fqn.fromString("/key3/level1")));
 383   
 384    /* Context nodes should still be intact. */
 385  1 assertTrue(loader.exists(new Fqn("key1")));
 386  1 assertTrue(loader.exists(new Fqn("key2")));
 387  1 assertTrue(loader.exists(new Fqn("key3")));
 388   
 389    /* Remove middle level only. */
 390  1 loader.remove(Fqn.fromString("/key3/level1"));
 391  1 assertTrue(!loader.exists(Fqn.fromString("/key3/level1/level2")));
 392  1 assertTrue(!loader.exists(Fqn.fromString("/key3/level1")));
 393   
 394    /* Context nodes should still be intact. */
 395  1 assertTrue(loader.exists(new Fqn("key1")));
 396  1 assertTrue(loader.exists(new Fqn("key2")));
 397  1 assertTrue(loader.exists(new Fqn("key3")));
 398   
 399    /* Delete first root, leaving other roots. */
 400  1 loader.remove(new Fqn("key1"));
 401  1 assertTrue(!loader.exists(new Fqn("key1")));
 402  1 assertTrue(loader.exists(new Fqn("key2")));
 403  1 assertTrue(loader.exists(new Fqn("key3")));
 404   
 405    /* Delete last root, leaving other roots. */
 406  1 loader.remove(new Fqn("key3"));
 407  1 assertTrue(loader.exists(new Fqn("key2")));
 408  1 assertTrue(!loader.exists(new Fqn("key3")));
 409   
 410    /* Delete final root, leaving none. */
 411  1 loader.remove(new Fqn("key2"));
 412  1 assertTrue(!loader.exists(new Fqn("key0")));
 413  1 assertTrue(!loader.exists(new Fqn("key1")));
 414  1 assertTrue(!loader.exists(new Fqn("key2")));
 415  1 assertTrue(!loader.exists(new Fqn("key3")));
 416   
 417    /* Repeat all tests above using put(Fqn,Object,Object) and get(Fqn) */
 418   
 419  1 assertNull(loader.get(new Fqn("key0")));
 420  1 loader.put(Fqn.fromString("/key0/level1/level2"), "a", "b");
 421  1 assertNotNull(loader.get(Fqn.fromString("/key0/level1/level2")));
 422  1 assertNotNull(loader.get(Fqn.fromString("/key0/level1")));
 423  1 assertNotNull(loader.get(new Fqn("key0")));
 424  1 assertEquals(0, loader.get(Fqn.fromString("/key0/level1")).size());
 425  1 assertEquals(0, loader.get(new Fqn("key0")).size());
 426   
 427   
 428  1 loader.put(Fqn.fromString("/key0/x/y"), "a", "b");
 429  1 assertNotNull(loader.get(Fqn.fromString("/key0/x/y")));
 430  1 assertNotNull(loader.get(Fqn.fromString("/key0/x")));
 431  1 assertEquals(0, loader.get(Fqn.fromString("/key0/x")).size());
 432  1 loader.remove(Fqn.fromString("/key0/x/y"));
 433  1 assertNull(loader.get(Fqn.fromString("/key0/x/y")));
 434  1 assertNotNull(loader.get(Fqn.fromString("/key0/x")));
 435  1 assertEquals(0, loader.get(Fqn.fromString("/key0/x")).size());
 436   
 437  1 loader.remove(new Fqn("key0"));
 438  1 assertNull(loader.get(new Fqn("key0")));
 439  1 assertNull(loader.get(Fqn.fromString("/key0/level1/level2")));
 440  1 assertNull(loader.get(Fqn.fromString("/key0/level1")));
 441  1 assertNull(loader.get(Fqn.fromString("/key0/x")));
 442   
 443  1 loader.put(new Fqn("key1"), "a", "b");
 444  1 loader.put(new Fqn("key2"), "a", "b");
 445  1 loader.put(new Fqn("key3"), "a", "b");
 446  1 assertNotNull(loader.get(new Fqn("key1")));
 447  1 assertNotNull(loader.get(new Fqn("key2")));
 448  1 assertNotNull(loader.get(new Fqn("key3")));
 449   
 450  1 assertNull(loader.get(Fqn.fromString("/key3/level1")));
 451  1 assertNull(loader.get(Fqn.fromString("/key3/level1/level2")));
 452  1 loader.put(Fqn.fromString("/key3/level1/level2"), "a", "b");
 453  1 assertNotNull(loader.get(Fqn.fromString("/key3/level1/level2")));
 454  1 assertNotNull(loader.get(Fqn.fromString("/key3/level1")));
 455  1 assertEquals(0, loader.get(Fqn.fromString("/key3/level1")).size());
 456   
 457  1 assertNotNull(loader.get(new Fqn("key1")));
 458  1 assertNotNull(loader.get(new Fqn("key2")));
 459  1 assertNotNull(loader.get(new Fqn("key3")));
 460   
 461  1 loader.remove(Fqn.fromString("/key3/level1"));
 462  1 assertNull(loader.get(Fqn.fromString("/key3/level1/level2")));
 463  1 assertNull(loader.get(Fqn.fromString("/key3/level1")));
 464   
 465  1 assertNotNull(loader.get(new Fqn("key1")));
 466  1 assertNotNull(loader.get(new Fqn("key2")));
 467  1 assertNotNull(loader.get(new Fqn("key3")));
 468   
 469  1 loader.remove(new Fqn("key1"));
 470  1 assertNull(loader.get(new Fqn("key1")));
 471  1 assertNotNull(loader.get(new Fqn("key2")));
 472  1 assertNotNull(loader.get(new Fqn("key3")));
 473   
 474  1 loader.remove(new Fqn("key3"));
 475  1 assertNotNull(loader.get(new Fqn("key2")));
 476  1 assertNull(loader.get(new Fqn("key3")));
 477   
 478  1 loader.remove(new Fqn("key2"));
 479  1 assertNull(loader.get(new Fqn("key0")));
 480  1 assertNull(loader.get(new Fqn("key1")));
 481  1 assertNull(loader.get(new Fqn("key2")));
 482  1 assertNull(loader.get(new Fqn("key3")));
 483   
 484  1 stopLoader();
 485    }
 486   
 487    /**
 488    * Tests the getChildrenNames() method.
 489    */
 490  1 public void testGetChildrenNames()
 491    throws Exception
 492    {
 493   
 494  1 startLoader(false, null);
 495   
 496  1 checkChildren(new Fqn(), null);
 497  1 checkChildren(Fqn.fromString("/key0"), null);
 498   
 499  1 loader.put(Fqn.fromString("/key0"), null);
 500  1 checkChildren(new Fqn(), new String[]{"key0"});
 501   
 502  1 loader.put(Fqn.fromString("/key1/x"), null);
 503  1 checkChildren(new Fqn(), new String[]{"key0", "key1"});
 504  1 checkChildren(Fqn.fromString("/key1"), new String[]{"x"});
 505   
 506  1 loader.remove(Fqn.fromString("/key1/x"));
 507  1 checkChildren(new Fqn(), new String[]{"key0", "key1"});
 508  1 checkChildren(Fqn.fromString("/key0"), null);
 509  1 checkChildren(Fqn.fromString("/key1"), null);
 510   
 511  1 loader.put(Fqn.fromString("/key0/a"), null);
 512  1 loader.put(Fqn.fromString("/key0/ab"), null);
 513  1 loader.put(Fqn.fromString("/key0/abc"), null);
 514  1 checkChildren(Fqn.fromString("/key0"),
 515    new String[]{"a", "ab", "abc"});
 516   
 517  1 loader.put(Fqn.fromString("/key0/xxx"), null);
 518  1 loader.put(Fqn.fromString("/key0/xx"), null);
 519  1 loader.put(Fqn.fromString("/key0/x"), null);
 520  1 checkChildren(Fqn.fromString("/key0"),
 521    new String[]{"a", "ab", "abc", "x", "xx", "xxx"});
 522   
 523  1 loader.put(Fqn.fromString("/key0/a/1"), null);
 524  1 loader.put(Fqn.fromString("/key0/a/2"), null);
 525  1 loader.put(Fqn.fromString("/key0/a/2/1"), null);
 526  1 checkChildren(Fqn.fromString("/key0/a/2"), new String[]{"1"});
 527  1 checkChildren(Fqn.fromString("/key0/a"), new String[]{"1", "2"});
 528  1 checkChildren(Fqn.fromString("/key0"),
 529    new String[]{"a", "ab", "abc", "x", "xx", "xxx"});
 530   
 531  1 loader.put(Fqn.fromString("/key0/\u0000"), null);
 532  1 loader.put(Fqn.fromString("/key0/\u0001"), null);
 533  1 checkChildren(Fqn.fromString("/key0"),
 534    new String[]{"a", "ab", "abc", "x", "xx", "xxx",
 535    "\u0000", "\u0001"});
 536   
 537  1 loader.put(Fqn.fromString("/\u0001"), null);
 538  1 checkChildren(new Fqn(), new String[]{"key0", "key1", "\u0001"});
 539   
 540  1 loader.put(Fqn.fromString("/\u0001/\u0001"), null);
 541  1 checkChildren(Fqn.fromString("/\u0001"), new String[]{"\u0001"});
 542   
 543  1 loader.put(Fqn.fromString("/\u0001/\uFFFF"), null);
 544  1 checkChildren(Fqn.fromString("/\u0001"),
 545    new String[]{"\u0001", "\uFFFF"});
 546   
 547  1 loader.put(Fqn.fromString("/\u0001/\uFFFF/\u0001"), null);
 548  1 checkChildren(Fqn.fromString("/\u0001/\uFFFF"),
 549    new String[]{"\u0001"});
 550   
 551  1 stopLoader();
 552    }
 553   
 554    /**
 555    * Checks that the given list of children part names is returned.
 556    */
 557  18 private void checkChildren(Fqn fqn, String[] names)
 558    throws Exception
 559    {
 560   
 561  18 Set set = loader.getChildrenNames(fqn);
 562  18 if (names != null)
 563    {
 564  14 assertEquals(names.length, set.size());
 565  14 for (int i = 0; i < names.length; i += 1)
 566    {
 567  39 assertTrue(set.contains(names[i]));
 568    }
 569    }
 570    else
 571    {
 572  4 assertNull(set);
 573    }
 574    }
 575   
 576    /**
 577    * Tests basic operations without a transaction.
 578    */
 579  1 public void testModifications()
 580    throws Exception
 581    {
 582   
 583  1 doTestModifications(false);
 584    }
 585   
 586    /**
 587    * Tests basic operations with a transaction.
 588    */
 589  1 public void testModificationsTransactional()
 590    throws Exception
 591    {
 592   
 593  1 doTestModifications(true);
 594    }
 595   
 596    /**
 597    * Tests modifications.
 598    */
 599  2 private void doTestModifications(boolean transactional)
 600    throws Exception
 601    {
 602   
 603  2 startLoader(transactional, null);
 604   
 605    /* PUT_KEY_VALUE, PUT_DATA */
 606  2 List list = createUpdates();
 607  2 loader.put(list);
 608  2 checkModifications(list);
 609   
 610    /* REMOVE_KEY_VALUE */
 611  2 list = new ArrayList();
 612  2 Modification mod = new Modification();
 613  2 mod.setType(Modification.ModificationType.REMOVE_KEY_VALUE);
 614  2 mod.setFqn(FQN);
 615  2 mod.setKey("one");
 616  2 list.add(mod);
 617  2 loader.put(list);
 618  2 checkModifications(list);
 619   
 620    /* REMOVE_NODE */
 621  2 list = new ArrayList();
 622  2 mod = new Modification();
 623  2 mod.setType(Modification.ModificationType.REMOVE_NODE);
 624  2 mod.setFqn(FQN);
 625  2 list.add(mod);
 626  2 loader.put(list);
 627  2 checkModifications(list);
 628  2 assertEquals(null, loader.get(FQN));
 629   
 630    /* REMOVE_DATA */
 631  2 loader.put(FQN, "one", "two");
 632  2 list = new ArrayList();
 633  2 mod = new Modification();
 634  2 mod.setType(Modification.ModificationType.REMOVE_DATA);
 635  2 mod.setFqn(FQN);
 636  2 list.add(mod);
 637  2 loader.put(list);
 638  2 checkModifications(list);
 639  2 assertNotNull(loader.get(FQN));
 640  2 assertEquals(0, loader.get(FQN).size());
 641   
 642  2 stopLoader();
 643    }
 644   
 645    /**
 646    * Tests a one-phase transaction.
 647    */
 648  1 public void testOnePhaseTransaction()
 649    throws Exception
 650    {
 651   
 652  1 startLoader(true, null);
 653   
 654  1 List mods = createUpdates();
 655  1 loader.prepare(null, mods, true);
 656  1 checkModifications(mods);
 657   
 658  1 stopLoader();
 659    }
 660   
 661    /**
 662    * Tests a two-phase transaction.
 663    */
 664  1 public void testTwoPhaseTransaction()
 665    throws Exception
 666    {
 667   
 668  1 startLoader(true, null);
 669   
 670  1 Object txnKey = new Object();
 671  1 List mods = createUpdates();
 672  1 loader.prepare(txnKey, mods, false);
 673  1 try
 674    {
 675  1 checkModifications(mods);
 676  0 fail("Expected lock timeout");
 677    }
 678    catch (DeadlockException expected)
 679    {
 680    }
 681  1 loader.commit(txnKey);
 682  1 checkModifications(mods);
 683   
 684  1 stopLoader();
 685    }
 686   
 687    /**
 688    * Tests rollback of a two-phase transaction.
 689    */
 690  1 public void testTransactionRollback()
 691    throws Exception
 692    {
 693   
 694  1 startLoader(true, null);
 695   
 696  1 Object txnKey = new Object();
 697  1 List mods = createUpdates();
 698  1 loader.prepare(txnKey, mods, false);
 699  1 loader.rollback(txnKey);
 700  1 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
 701  1 MarshalledValueOutputStream os = new MarshalledValueOutputStream(baos);
 702  1 loader.loadEntireState(os);
 703  1 os.close();
 704   
 705  1 stopLoader();
 706    }
 707   
 708    /**
 709    * Creates a set of update (PUT_KEY_VALUE, PUT_DATA) modifications.
 710    */
 711  6 private List createUpdates()
 712    {
 713   
 714  6 List list = new ArrayList();
 715   
 716  6 Modification mod = new Modification();
 717  6 mod.setType(Modification.ModificationType.PUT_KEY_VALUE);
 718  6 mod.setFqn(FQN);
 719  6 mod.setKey("one");
 720  6 mod.setValue("two");
 721  6 list.add(mod);
 722   
 723  6 mod = new Modification();
 724  6 mod.setType(Modification.ModificationType.PUT_KEY_VALUE);
 725  6 mod.setFqn(FQN);
 726  6 mod.setKey("three");
 727  6 mod.setValue("four");
 728  6 list.add(mod);
 729   
 730  6 Map map = new HashMap();
 731  6 map.put("five", "six");
 732  6 map.put("seven", "eight");
 733  6 mod = new Modification();
 734  6 mod.setType(Modification.ModificationType.PUT_DATA);
 735  6 mod.setFqn(FQN);
 736  6 mod.setData(map);
 737  6 list.add(mod);
 738   
 739  6 return list;
 740    }
 741   
 742    /**
 743    * Checks that a list of modifications was applied.
 744    */
 745  11 private void checkModifications(List list)
 746    throws Exception
 747    {
 748   
 749  11 for (int i = 0; i < list.size(); i += 1)
 750    {
 751  19 Modification mod = (Modification) list.get(i);
 752  19 Fqn fqn = mod.getFqn();
 753  19 switch (mod.getType())
 754    {
 755  9 case PUT_KEY_VALUE:
 756  9 assertEquals(mod.getValue(), loader.get(fqn).get(mod.getKey()));
 757  8 break;
 758  4 case PUT_DATA:
 759  4 Map map = mod.getData();
 760  4 for (Object key : map.keySet())
 761    {
 762  8 assertEquals(map.get(key), loader.get(fqn).get(key));
 763    }
 764  4 break;
 765  2 case REMOVE_KEY_VALUE:
 766  2 assertEquals(null, loader.get(fqn).get(mod.getKey()));
 767  2 break;
 768  2 case REMOVE_DATA:
 769  2 assertTrue(loader.exists(fqn));
 770  2 assertNotNull(loader.get(fqn));
 771  2 assertEquals(0, loader.get(fqn).size());
 772  2 break;
 773  2 case REMOVE_NODE:
 774  2 assertTrue(!loader.exists(fqn));
 775  2 assertEquals(null, loader.get(fqn));
 776  2 break;
 777  0 default:
 778  0 fail("unknown type: " + mod);
 779  0 break;
 780    }
 781    }
 782    }
 783   
 784    /**
 785    * Test exception cases and create/destroy/create/destroy sequence.
 786    */
 787    // public void testBasicExceptions()
 788    // throws Exception {
 789    //
 790    // instantiateLoader();
 791    // checkPreCreateExceptions();
 792    //
 793    // startLoader(false, null);
 794    // checkPostCreateExceptions();
 795    // loader.put(FQN, "one", "two");
 796    // assertEquals("two", loader.get(FQN).get("one"));
 797    //
 798    // stopLoader();
 799    // checkPreCreateExceptions();
 800    //
 801    // startLoader(false, null);
 802    // checkPostCreateExceptions();
 803    // loader.put(FQN, "one", "two");
 804    // assertEquals("two", loader.get(FQN).get("one"));
 805    //
 806    // stopLoader();
 807    // checkPreCreateExceptions();
 808    // }
 809   
 810    /**
 811    * Check exception cases that occur before create().
 812    */
 813  0 private void checkPreCreateExceptions()
 814    throws Exception
 815    {
 816   
 817  0 loader.setCache((CacheSPI) DefaultCacheFactory.getInstance().createCache(false));
 818  0 loader.setConfig(null);
 819  0 try
 820    {
 821  0 loader.start();
 822    // fail();
 823    }
 824    catch (IllegalStateException expected)
 825    {
 826    }
 827   
 828    // loader.setCache(null);
 829  0 BdbjeCacheLoaderConfig config = new BdbjeCacheLoaderConfig();
 830  0 config.setLocation("xyz");
 831  0 loader.setConfig(config);
 832  0 try
 833    {
 834  0 loader.start();
 835  0 fail();
 836    }
 837    catch (IllegalStateException expected)
 838    {
 839    }
 840   
 841  0 loader.setCache((CacheSPI) DefaultCacheFactory.getInstance().createCache(false));
 842  0 config = new BdbjeCacheLoaderConfig();
 843  0 config.setLocation("directory_that_does_not_exist");
 844  0 loader.setConfig(config);
 845  0 try
 846    {
 847  0 loader.start();
 848  0 fail();
 849    }
 850    catch (DatabaseException expected)
 851    {
 852    }
 853   
 854  0 try
 855    {
 856  0 loader.put(FQN, "one", "two");
 857  0 fail();
 858    }
 859    catch (IllegalStateException expected)
 860    {
 861    }
 862   
 863  0 try
 864    {
 865  0 loader.put(FQN, new HashMap());
 866  0 fail();
 867    }
 868    catch (IllegalStateException expected)
 869    {
 870    }
 871   
 872  0 try
 873    {
 874  0 loader.put(new ArrayList());
 875  0 fail();
 876    }
 877    catch (IllegalStateException expected)
 878    {
 879    }
 880   
 881  0 try
 882    {
 883  0 loader.get(FQN).get("one");
 884  0 fail();
 885    }
 886    catch (IllegalStateException expected)
 887    {
 888    }
 889   
 890  0 try
 891    {
 892  0 loader.get(FQN);
 893  0 fail();
 894    }
 895    catch (IllegalStateException expected)
 896    {
 897    }
 898   
 899  0 try
 900    {
 901  0 loader.remove(FQN);
 902  0 fail();
 903    }
 904    catch (IllegalStateException expected)
 905    {
 906    }
 907   
 908  0 try
 909    {
 910  0 loader.remove(FQN, "one");
 911  0 fail();
 912    }
 913    catch (IllegalStateException expected)
 914    {
 915    }
 916   
 917  0 try
 918    {
 919  0 loader.prepare(new Object(), new ArrayList(), false);
 920  0 fail();
 921    }
 922    catch (IllegalStateException expected)
 923    {
 924    }
 925   
 926  0 try
 927    {
 928  0 loader.commit(new Object());
 929  0 fail();
 930    }
 931    catch (IllegalStateException expected)
 932    {
 933    }
 934   
 935  0 try
 936    {
 937  0 loader.rollback(new Object());
 938  0 fail();
 939    }
 940    catch (IllegalStateException expected)
 941    {
 942    }
 943   
 944  0 try
 945    {
 946  0 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
 947  0 MarshalledValueOutputStream os = new MarshalledValueOutputStream(baos);
 948  0 loader.loadEntireState(os);
 949  0 fail();
 950    }
 951    catch (IllegalStateException expected)
 952    {
 953    }
 954   
 955  0 try
 956    {
 957  0 ByteArrayInputStream baos = new ByteArrayInputStream(new byte[0]);
 958  0 MarshalledValueInputStream is = new MarshalledValueInputStream(baos);
 959  0 loader.storeEntireState(is);
 960  0 fail();
 961    }
 962    catch (IllegalStateException expected)
 963    {
 964    }
 965   
 966    /* Redundant stop and destroy are allowed. */
 967  0 loader.stop();
 968  0 loader.destroy();
 969    }
 970   
 971    /**
 972    * Check exception cases that occur after create().
 973    */
 974  0 private void checkPostCreateExceptions()
 975    throws Exception
 976    {
 977   
 978  0 try
 979    {
 980  0 loader.create();
 981  0 fail();
 982    }
 983    catch (IllegalStateException expected)
 984    {
 985    }
 986   
 987  0 try
 988    {
 989  0 loader.start();
 990  0 fail();
 991    }
 992    catch (IllegalStateException expected)
 993    {
 994    }
 995   
 996  0 try
 997    {
 998  0 loader.put(null, "one", "two");
 999  0 fail();
 1000    }
 1001    catch (NullPointerException expected)
 1002    {
 1003    }
 1004   
 1005  0 try
 1006    {
 1007  0 loader.put(null, new HashMap());
 1008  0 fail();
 1009    }
 1010    catch (NullPointerException expected)
 1011    {
 1012    }
 1013   
 1014  0 try
 1015    {
 1016  0 loader.put(null);
 1017  0 fail();
 1018    }
 1019    catch (NullPointerException expected)
 1020    {
 1021    }
 1022   
 1023  0 try
 1024    {
 1025  0 loader.get(null).get("one");
 1026  0 fail();
 1027    }
 1028    catch (NullPointerException expected)
 1029    {
 1030    }
 1031   
 1032  0 try
 1033    {
 1034  0 loader.get(null);
 1035  0 fail();
 1036    }
 1037    catch (NullPointerException expected)
 1038    {
 1039    }
 1040   
 1041  0 try
 1042    {
 1043  0 loader.remove(null);
 1044  0 fail();
 1045    }
 1046    catch (NullPointerException expected)
 1047    {
 1048    }
 1049   
 1050  0 try
 1051    {
 1052  0 loader.remove(null, "one");
 1053  0 fail();
 1054    }
 1055    catch (NullPointerException expected)
 1056    {
 1057    }
 1058   
 1059  0 try
 1060    {
 1061  0 loader.prepare(null, new ArrayList(), false);
 1062  0 fail();
 1063    }
 1064    catch (NullPointerException expected)
 1065    {
 1066    }
 1067  0 try
 1068    {
 1069  0 loader.prepare(new Object(), null, false);
 1070  0 fail();
 1071    }
 1072    catch (NullPointerException expected)
 1073    {
 1074    }
 1075   
 1076  0 try
 1077    {
 1078  0 loader.commit(null);
 1079  0 fail();
 1080    }
 1081    catch (NullPointerException expected)
 1082    {
 1083    }
 1084   
 1085  0 try
 1086    {
 1087  0 loader.rollback(null);
 1088  0 fail();
 1089    }
 1090    catch (NullPointerException expected)
 1091    {
 1092    }
 1093    }
 1094   
 1095    /**
 1096    * Tests a non-transactional prepare.
 1097    */
 1098  1 public void testTransactionExceptions()
 1099    throws Exception
 1100    {
 1101   
 1102  1 List mods = createUpdates();
 1103   
 1104    /* A non-transactional cache loader should not allow prepare(). */
 1105  1 startLoader(false, null);
 1106  1 try
 1107    {
 1108  1 loader.prepare(new Object(), mods, false);
 1109  0 fail();
 1110    }
 1111    catch (UnsupportedOperationException expected)
 1112    {
 1113    }
 1114  1 stopLoader();
 1115   
 1116  1 startLoader(true, null);
 1117   
 1118    /* Commit and rollback a non-prepared transaction. */
 1119  1 try
 1120    {
 1121  1 loader.commit(new Object());
 1122  0 fail();
 1123    }
 1124    catch (IllegalArgumentException expected)
 1125    {
 1126    }
 1127  1 try
 1128    {
 1129  1 loader.rollback(new Object());
 1130  0 fail();
 1131    }
 1132    catch (IllegalArgumentException expected)
 1133    {
 1134    }
 1135   
 1136    /* Commit and rollback after commit. */
 1137   
 1138  1 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
 1139  1 MarshalledValueOutputStream os = new MarshalledValueOutputStream(baos);
 1140  1 cache.getMarshaller().objectToObjectStream(StateTransferManager.STREAMING_DELIMITER_NODE, os);
 1141  1 os.close();
 1142   
 1143  1 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 1144  1 MarshalledValueInputStream is = new MarshalledValueInputStream(bais);
 1145  1 loader.storeEntireState(is);
 1146  1 is.close();
 1147   
 1148  1 Object txnKey = new Object();
 1149  1 loader.prepare(txnKey, mods, false);
 1150  1 loader.commit(txnKey);
 1151  1 try
 1152    {
 1153  1 loader.commit(txnKey);
 1154  0 fail();
 1155    }
 1156    catch (IllegalArgumentException expected)
 1157    {
 1158    }
 1159  1 try
 1160    {
 1161  1 loader.rollback(txnKey);
 1162  0 fail();
 1163    }
 1164    catch (IllegalArgumentException expected)
 1165    {
 1166    }
 1167   
 1168    /* Commit and rollback after rollback. */
 1169  1 bais = new ByteArrayInputStream(baos.toByteArray());
 1170  1 is = new MarshalledValueInputStream(bais);
 1171  1 loader.storeEntireState(is);
 1172  1 is.close();
 1173  1 txnKey = new Object();
 1174  1 loader.prepare(txnKey, mods, false);
 1175  1 loader.rollback(txnKey);
 1176  1 try
 1177    {
 1178  1 loader.rollback(txnKey);
 1179  0 fail();
 1180    }
 1181    catch (IllegalArgumentException expected)
 1182    {
 1183    }
 1184  1 try
 1185    {
 1186  1 loader.rollback(txnKey);
 1187  0 fail();
 1188    }
 1189    catch (IllegalArgumentException expected)
 1190    {
 1191    }
 1192   
 1193  1 stopLoader();
 1194    }
 1195   
 1196    /**
 1197    * Tests that null keys and values work as for a standard Java Map.
 1198    */
 1199  1 public void testNullKeysAndValues()
 1200    throws Exception
 1201    {
 1202   
 1203  1 startLoader(false, null);
 1204   
 1205  1 loader.put(FQN, null, "x");
 1206  1 assertEquals("x", loader.get(FQN).get(null));
 1207  1 Map map = loader.get(FQN);
 1208  1 assertEquals(1, map.size());
 1209  1 assertEquals("x", map.get(null));
 1210   
 1211  1 loader.put(FQN, "y", null);
 1212  1 assertEquals(null, loader.get(FQN).get("y"));
 1213  1 map = loader.get(FQN);
 1214  1 assertEquals(2, map.size());
 1215  1 assertEquals("x", map.get(null));
 1216  1 assertEquals(null, map.get("y"));
 1217   
 1218  1 loader.remove(FQN, null);
 1219  1 assertEquals(null, loader.get(FQN).get(null));
 1220  1 assertEquals(1, loader.get(FQN).size());
 1221   
 1222  1 loader.remove(FQN, "y");
 1223  1 assertNotNull(loader.get(FQN));
 1224  1 assertEquals(0, loader.get(FQN).size());
 1225   
 1226  1 map = new HashMap();
 1227  1 map.put(null, null);
 1228  1 loader.put(FQN, map);
 1229  1 assertEquals(map, loader.get(FQN));
 1230   
 1231  1 loader.remove(FQN);
 1232  1 assertNull("Should be null", loader.get(FQN));
 1233   
 1234  1 map = new HashMap();
 1235  1 map.put("xyz", null);
 1236  1 map.put(null, "abc");
 1237  1 loader.put(FQN, map);
 1238  1 assertEquals(map, loader.get(FQN));
 1239   
 1240  1 loader.remove(FQN);
 1241  1 assertEquals(null, loader.get(FQN));
 1242   
 1243  1 stopLoader();
 1244    }
 1245   
 1246    /**
 1247    * Test non-default database name.
 1248    */
 1249  1 public void testDatabaseName()
 1250    throws Exception
 1251    {
 1252   
 1253  1 startLoader(false, "nonDefaultDbName");
 1254  1 loader.put(FQN, "one", "two");
 1255  1 assertEquals("two", loader.get(FQN).get("one"));
 1256  1 stopLoader();
 1257    }
 1258   
 1259    /**
 1260    * Test load/store state.
 1261    */
 1262  1 public void testLoadAndStore()
 1263    throws Exception
 1264    {
 1265   
 1266  1 startLoader(false, null);
 1267   
 1268    /* Empty state. */
 1269  1 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
 1270  1 MarshalledValueOutputStream os = new MarshalledValueOutputStream(baos);
 1271  1 loader.loadEntireState(os);
 1272  1 cache.getMarshaller().objectToObjectStream(StateTransferManager.STREAMING_DELIMITER_NODE, os);
 1273  1 os.close();
 1274   
 1275  1 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 1276  1 MarshalledValueInputStream is = new MarshalledValueInputStream(bais);
 1277  1 loader.storeEntireState(is);
 1278  1 is.close();
 1279   
 1280  1 baos = new ByteArrayOutputStream(1024);
 1281  1 os = new MarshalledValueOutputStream(baos);
 1282  1 loader.loadEntireState(os);
 1283  1 cache.getMarshaller().objectToObjectStream(StateTransferManager.STREAMING_DELIMITER_NODE, os);
 1284  1 os.close();
 1285   
 1286  1 bais = new ByteArrayInputStream(baos.toByteArray());
 1287  1 is = new MarshalledValueInputStream(bais);
 1288  1 loader.storeEntireState(is);
 1289  1 is.close();
 1290   
 1291  1 baos = new ByteArrayOutputStream(1024);
 1292  1 os = new MarshalledValueOutputStream(baos);
 1293  1 loader.loadEntireState(os);
 1294  1 cache.getMarshaller().objectToObjectStream(StateTransferManager.STREAMING_DELIMITER_NODE, os);
 1295  1 os.close();
 1296   
 1297  1 assertEquals(null, loader.get(FQN));
 1298   
 1299    /* Use a complex object to ensure that the class catalog is used. */
 1300  1 Complex c1 = new Complex();
 1301  1 Complex c2 = new Complex(c1);
 1302   
 1303    /* Add objects. */
 1304  1 loader.put(FQN, 1, c1);
 1305  1 loader.put(FQN, 2, c2);
 1306  1 assertEquals(c1, loader.get(FQN).get(1));
 1307  1 assertEquals(c2, loader.get(FQN).get(2));
 1308  1 assertEquals(2, loader.get(FQN).size());
 1309   
 1310    /* Save state. */
 1311  1 baos = new ByteArrayOutputStream(1024);
 1312  1 os = new MarshalledValueOutputStream(baos);
 1313  1 loader.loadEntireState(os);
 1314  1 cache.getMarshaller().objectToObjectStream(StateTransferManager.STREAMING_DELIMITER_NODE, os);
 1315  1 assertTrue(baos.size() > STREAM_HEADER_LENGTH);
 1316  1 os.close();
 1317   
 1318  1 byte[] savedState = baos.toByteArray();
 1319   
 1320    /* Clear state. */
 1321  1 baos = new ByteArrayOutputStream(1024);
 1322  1 os = new MarshalledValueOutputStream(baos);
 1323  1 cache.getMarshaller().objectToObjectStream(StateTransferManager.STREAMING_DELIMITER_NODE, os);
 1324  1 os.close();
 1325  1 bais = new ByteArrayInputStream(baos.toByteArray());
 1326  1 is = new MarshalledValueInputStream(bais);
 1327  1 loader.storeEntireState(is);
 1328  1 is.close();
 1329   
 1330  1 assertEquals(null, loader.get(FQN));
 1331   
 1332    /* Restore state. */
 1333  1 bais = new ByteArrayInputStream(savedState);
 1334  1 is = new MarshalledValueInputStream(bais);
 1335  1 loader.storeEntireState(is);
 1336  1 is.close();
 1337  1 assertEquals(c1, loader.get(FQN).get(1));
 1338  1 assertEquals(c2, loader.get(FQN).get(2));
 1339  1 assertEquals(2, loader.get(FQN).size());
 1340   
 1341  1 stopLoader();
 1342    }
 1343   
 1344  1 public static Test suite()
 1345    throws Exception
 1346    {
 1347   
 1348  1 return new TestSuite(BdbjeTest.class);
 1349    }
 1350   
 1351  0 public static void main(String[] args)
 1352    throws Exception
 1353    {
 1354   
 1355  0 junit.textui.TestRunner.run(suite());
 1356    }
 1357   
 1358    /**
 1359    * Complex object whose class description is stored in the class catalog.
 1360    */
 1361    private static class Complex implements Serializable
 1362    {
 1363    /**
 1364    * The serialVersionUID
 1365    */
 1366    private static final long serialVersionUID = -1259096627833244770L;
 1367   
 1368    Complex nested;
 1369   
 1370  1 Complex()
 1371    {
 1372  1 this(null);
 1373    }
 1374   
 1375  2 Complex(Complex nested)
 1376    {
 1377  2 this.nested = nested;
 1378    }
 1379   
 1380  6 public boolean equals(Object o)
 1381    {
 1382  6 try
 1383    {
 1384  6 Complex x = (Complex) o;
 1385  6 return (nested != null) ? nested.equals(x.nested)
 1386    : (x.nested == null);
 1387    }
 1388    catch (ClassCastException e)
 1389    {
 1390  0 return false;
 1391    }
 1392    }
 1393    }
 1394    }