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