Clover coverage report -
Coverage timestamp: Wed Jan 31 2007 15:38:53 EST
file stats: LOC: 557   Methods: 15
NCLOC: 377   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
NodeMoveAPITest.java 53.8% 84.7% 86.7% 82.3%
coverage coverage
 1    package org.jboss.cache.api;
 2   
 3    import org.jboss.cache.CacheImpl;
 4    import org.jboss.cache.DefaultCacheFactory;
 5    import org.jboss.cache.Fqn;
 6    import org.jboss.cache.Node;
 7    import org.jboss.cache.NodeNotExistsException;
 8    import org.jboss.cache.config.Configuration;
 9    import org.jboss.cache.loader.AbstractCacheLoaderTestBase;
 10    import org.jboss.cache.loader.DummyInMemoryCacheLoader;
 11    import org.jboss.cache.misc.TestingUtil;
 12   
 13    import javax.transaction.TransactionManager;
 14    import java.util.Random;
 15    import java.util.concurrent.CountDownLatch;
 16   
 17    /**
 18    * Excercises and tests the new move() api
 19    *
 20    * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
 21    * @since 2.0.0
 22    */
 23    public class NodeMoveAPITest extends AbstractCacheLoaderTestBase
 24    {
 25   
 26    protected Node rootNode, nodeA, nodeB, nodeC, nodeD, nodeE;
 27    protected CacheImpl cache;
 28    protected TransactionManager tm;
 29    protected static final Fqn A = Fqn.fromString("/a"), B = Fqn.fromString("/b"), C = Fqn.fromString("/c"), D = Fqn.fromString("/d"), E = Fqn.fromString("/e");
 30    protected Object k = "key", vA = "valueA", vB = "valueB", vC = "valueC", vD = "valueD", vE = "valueE";
 31   
 32    protected boolean optimistic = false;
 33   
 34   
 35  20 protected void setUp() throws Exception
 36    {
 37    // start a single cache instance
 38  20 cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache("META-INF/local-tx-service.xml", false);
 39  20 cache.getConfiguration().setNodeLockingScheme(optimistic ? Configuration.NodeLockingScheme.OPTIMISTIC : Configuration.NodeLockingScheme.PESSIMISTIC);
 40  20 cache.start();
 41  20 rootNode = cache.getRoot();
 42  20 tm = cache.getTransactionManager();
 43    }
 44   
 45  20 protected void tearDown()
 46    {
 47  20 if (cache != null) cache.stop();
 48  20 if (rootNode != null) rootNode = null;
 49    }
 50   
 51   
 52  2 public void testBasicMove()
 53    {
 54  2 nodeA = rootNode.addChild(A);
 55  2 nodeA.put(k, vA);
 56  2 nodeB = rootNode.addChild(B);
 57  2 nodeB.put(k, vB);
 58  2 nodeC = nodeA.addChild(C);
 59  2 nodeC.put(k, vC);
 60    /*
 61    /a/c
 62    /b
 63    */
 64   
 65  2 assertTrue(rootNode.hasChild(A));
 66  2 assertTrue(rootNode.hasChild(B));
 67  2 assertFalse(rootNode.hasChild(C));
 68  2 assertTrue(nodeA.hasChild(C));
 69   
 70    // test data
 71  2 assertEquals("" + nodeA, vA, nodeA.get(k));
 72  2 assertEquals(vB, nodeB.get(k));
 73  2 assertEquals(vC, nodeC.get(k));
 74   
 75    // parentage
 76  2 assertEquals(nodeA, nodeC.getParent());
 77   
 78  2 log.info("BEFORE MOVE " + cache);
 79    // move
 80  2 cache.move(nodeC.getFqn(), nodeB.getFqn());
 81   
 82    // re-fetch nodeC
 83  2 nodeC = cache.get(new Fqn(nodeB.getFqn(), C));
 84   
 85  2 log.info("POST MOVE " + cache);
 86  2 log.info("HC " + nodeC + " " + System.identityHashCode(nodeC));
 87  2 Node x = cache.getRoot().getChild(Fqn.fromString("b/c"));
 88  2 log.info("HC " + x + " " + System.identityHashCode(x));
 89    /*
 90    /a
 91    /b/c
 92    */
 93  2 assertEquals("NODE C " + nodeC, "/b/c", nodeC.getFqn().toString());
 94   
 95  2 assertTrue(rootNode.hasChild(A));
 96  2 assertTrue(rootNode.hasChild(B));
 97  2 assertFalse(rootNode.hasChild(C));
 98  2 assertFalse(nodeA.hasChild(C));
 99  2 assertTrue(nodeB.hasChild(C));
 100   
 101    // test data
 102  2 assertEquals(vA, nodeA.get(k));
 103  2 assertEquals(vB, nodeB.get(k));
 104  2 assertEquals(vC, nodeC.get(k));
 105   
 106    // parentage
 107  2 assertEquals("B is parent of C: " + nodeB, nodeB, nodeC.getParent());
 108    }
 109   
 110  2 public void testMoveWithChildren()
 111    {
 112  2 nodeA = rootNode.addChild(A);
 113  2 nodeA.put(k, vA);
 114  2 nodeB = rootNode.addChild(B);
 115  2 nodeB.put(k, vB);
 116  2 nodeC = nodeA.addChild(C);
 117  2 nodeC.put(k, vC);
 118  2 nodeD = nodeC.addChild(D);
 119  2 nodeD.put(k, vD);
 120  2 nodeE = nodeD.addChild(E);
 121  2 nodeE.put(k, vE);
 122   
 123  2 assertTrue(rootNode.hasChild(A));
 124  2 assertTrue(rootNode.hasChild(B));
 125  2 assertFalse(rootNode.hasChild(C));
 126  2 assertTrue(nodeA.hasChild(C));
 127  2 assertTrue(nodeC.hasChild(D));
 128  2 assertTrue(nodeD.hasChild(E));
 129   
 130    // test data
 131  2 assertEquals(vA, nodeA.get(k));
 132  2 assertEquals(vB, nodeB.get(k));
 133  2 assertEquals(vC, nodeC.get(k));
 134  2 assertEquals(vD, nodeD.get(k));
 135  2 assertEquals(vE, nodeE.get(k));
 136   
 137    // parentage
 138  2 assertEquals(rootNode, nodeA.getParent());
 139  2 assertEquals(rootNode, nodeB.getParent());
 140  2 assertEquals(nodeA, nodeC.getParent());
 141  2 assertEquals(nodeC, nodeD.getParent());
 142  2 assertEquals(nodeD, nodeE.getParent());
 143   
 144    // move
 145  2 log.info("move " + nodeC + " to " + nodeB);
 146  2 cache.move(nodeC.getFqn(), nodeB.getFqn());
 147    //System.out.println("nodeB " + nodeB);
 148    //System.out.println("nodeC " + nodeC);
 149   
 150    // child nodes will need refreshing, since existing pointers will be stale.
 151  2 nodeC = nodeB.getChild(C);
 152  2 nodeD = nodeC.getChild(D);
 153  2 nodeE = nodeD.getChild(E);
 154   
 155  2 System.out.println("Tree " + cache.printLockInfo());
 156   
 157  2 assertTrue(rootNode.hasChild(A));
 158  2 assertTrue(rootNode.hasChild(B));
 159  2 assertFalse(rootNode.hasChild(C));
 160  2 assertFalse(nodeA.hasChild(C));
 161  2 assertTrue(nodeB.hasChild(C));
 162  2 assertTrue(nodeC.hasChild(D));
 163  2 assertTrue(nodeD.hasChild(E));
 164   
 165    // test data
 166  2 assertEquals(vA, nodeA.get(k));
 167  2 assertEquals(vB, nodeB.get(k));
 168  2 assertEquals(vC, nodeC.get(k));
 169  2 assertEquals(vD, nodeD.get(k));
 170  2 assertEquals(vE, nodeE.get(k));
 171   
 172    // parentage
 173  2 assertEquals(rootNode, nodeA.getParent());
 174  2 assertEquals(rootNode, nodeB.getParent());
 175  2 assertEquals(nodeB, nodeC.getParent());
 176  2 assertEquals(nodeC, nodeD.getParent());
 177  2 assertEquals(nodeD, nodeE.getParent());
 178    }
 179   
 180  2 public void testTxCommit() throws Exception
 181    {
 182  2 nodeA = rootNode.addChild(A);
 183  2 nodeB = nodeA.addChild(B);
 184   
 185  2 assertEquals(rootNode, nodeA.getParent());
 186  2 assertEquals(nodeA, nodeB.getParent());
 187  2 assertEquals(nodeA, rootNode.getChildren().iterator().next());
 188  2 assertEquals(nodeB, nodeA.getChildren().iterator().next());
 189   
 190  2 tm.begin();
 191    // move node B up to hang off the root
 192  2 cache.move(nodeB.getFqn(), Fqn.ROOT);
 193   
 194  2 tm.commit();
 195   
 196  2 nodeB = rootNode.getChild(B);
 197   
 198  2 assertEquals(rootNode, nodeA.getParent());
 199  2 assertEquals(rootNode, nodeB.getParent());
 200   
 201  2 assertTrue(rootNode.getChildren().contains(nodeA));
 202  2 assertTrue(rootNode.getChildren().contains(nodeB));
 203   
 204  2 assertTrue(nodeA.getChildren().isEmpty());
 205    }
 206   
 207  2 public void testTxRollback() throws Exception
 208    {
 209  2 nodeA = rootNode.addChild(A);
 210  2 nodeB = nodeA.addChild(B);
 211   
 212  2 assertEquals(rootNode, nodeA.getParent());
 213  2 assertEquals(nodeA, nodeB.getParent());
 214  2 assertEquals(nodeA, rootNode.getChildren().iterator().next());
 215  2 assertEquals(nodeB, nodeA.getChildren().iterator().next());
 216   
 217   
 218  2 tm.begin();
 219    // move node B up to hang off the root
 220  2 cache.move(nodeB.getFqn(), Fqn.ROOT);
 221   
 222    // need to think of a way to test the same with optimistically locked nodes
 223  2 if (!optimistic)
 224    {
 225  1 assertEquals(rootNode, nodeA.getParent());
 226  1 assertEquals(rootNode, nodeB.getParent());
 227  1 assertTrue(rootNode.getChildren().contains(nodeA));
 228  1 assertTrue(rootNode.getChildren().contains(nodeB));
 229  1 assertTrue(nodeA.getChildren().isEmpty());
 230    }
 231   
 232   
 233  2 tm.rollback();
 234   
 235  2 nodeA = rootNode.getChild(A);
 236  2 nodeB = nodeA.getChild(B);
 237   
 238    // should revert
 239  2 assertEquals(rootNode, nodeA.getParent());
 240  2 assertEquals(nodeA, nodeB.getParent());
 241  2 assertEquals(nodeA, rootNode.getChildren().iterator().next());
 242  2 assertEquals(nodeB, nodeA.getChildren().iterator().next());
 243    }
 244   
 245  2 public void testWithCacheloaders() throws Exception
 246    {
 247  2 doCacheLoaderTest(false, false);
 248    }
 249   
 250  2 public void testWithPassivation() throws Exception
 251    {
 252  2 doCacheLoaderTest(true, false);
 253    }
 254   
 255  2 public void testWithCacheloadersTx() throws Exception
 256    {
 257  2 doCacheLoaderTest(false, true);
 258    }
 259   
 260  2 public void testWithPassivationTx() throws Exception
 261    {
 262  2 doCacheLoaderTest(true, true);
 263    }
 264   
 265  8 protected void doCacheLoaderTest(boolean pasv, boolean useTx) throws Exception
 266    {
 267  8 cache.stop();
 268  8 cache.getConfiguration().setCacheLoaderConfig(getSingleCacheLoaderConfig(pasv, "", DummyInMemoryCacheLoader.class.getName(), null, false, false, false, false));
 269  8 cache.start();
 270   
 271  8 DummyInMemoryCacheLoader loader = (DummyInMemoryCacheLoader) cache.getCacheLoaderManager().getCacheLoader();
 272   
 273  8 rootNode.put("key", "value");
 274   
 275  4 if (!pasv) assertEquals("value", loader.get(Fqn.ROOT).get("key"));
 276   
 277  8 nodeA = rootNode.addChild(A);
 278  8 nodeA.put(k, vA);
 279  8 nodeB = rootNode.addChild(B);
 280  8 nodeB.put(k, vB);
 281  8 nodeC = nodeA.addChild(C);
 282  8 nodeC.put(k, vC);
 283  8 nodeD = nodeC.addChild(D);
 284  8 nodeD.put(k, vD);
 285  8 nodeE = nodeD.addChild(E);
 286  8 nodeE.put(k, vE);
 287    /*
 288    Node nodeF = nodeE.addChild(Fqn.fromString("F"));
 289    nodeF.put(k, vE);
 290    Node nodeG = nodeF.addChild(Fqn.fromString("G"));
 291    nodeG.put(k, vE);
 292    */
 293   
 294  8 assertNotNull(cache.peek(A, false));
 295  8 assertNotNull(cache.peek(B, false));
 296  8 assertNull(cache.peek(C, false));
 297  8 assertNotNull(cache.peek(new Fqn(A, C), false));
 298  8 assertNotNull(cache.peek(new Fqn(new Fqn(A, C), D), false));
 299  8 assertNotNull(cache.peek(new Fqn(new Fqn(new Fqn(A, C), D), E), false));
 300   
 301    // test data
 302  8 assertEquals(vA, nodeA.get(k));
 303  8 assertEquals(vB, nodeB.get(k));
 304  8 assertEquals(vC, nodeC.get(k));
 305  8 assertEquals(vD, nodeD.get(k));
 306  8 assertEquals(vE, nodeE.get(k));
 307   
 308    // parentage
 309  8 assertEquals(rootNode, nodeA.getParent());
 310  8 assertEquals(rootNode, nodeB.getParent());
 311  8 assertEquals(nodeA, nodeC.getParent());
 312  8 assertEquals(nodeC, nodeD.getParent());
 313  8 assertEquals(nodeD, nodeE.getParent());
 314   
 315  8 System.out.println("Loader" + loader);
 316   
 317  8 log.info("Current tree is " + cache.printDetails());
 318   
 319  8 cache.evict(Fqn.ROOT, true);
 320   
 321  8 log.info("POST EVICT tree is " + cache.printDetails());
 322   
 323    // move
 324  4 if (useTx) tm.begin();
 325  8 cache.move(nodeC.getFqn(), nodeB.getFqn());
 326   
 327    // Fqn[] fqns = {A, B, new Fqn(B, C), new Fqn(new Fqn(B, C), D), new Fqn(new Fqn(new Fqn(B, C), D), E)};
 328    // System.out.println("*** LOADER BEFORE COMMIT ");
 329    // for (Fqn f: fqns)
 330    // {
 331    // System.out.println(" Fqn: " + f);
 332    // System.out.println(" Contents in loader: " + loader.get(f));
 333    // }
 334  4 if (useTx) tm.commit();
 335    // System.out.println("*** LOADER AFTER COMMIT ");
 336    // for (Fqn f: fqns)
 337    // {
 338    // System.out.println(" Fqn: " + f);
 339    // System.out.println(" Contents in loader: " + loader.get(f));
 340    // }
 341   
 342  8 log.info("Post commit tree is " + cache.printDetails());
 343   
 344    // after eviction, the node objects we hold are probably stale.
 345  8 nodeA = rootNode.getChild(A);
 346  8 nodeB = rootNode.getChild(B);
 347  8 nodeC = nodeB.getChild(C);
 348  8 log.info("Current tree is " + cache.printDetails());
 349  8 log.info("nodeC get child B ");
 350  8 nodeD = nodeC.getChild(D);
 351  8 log.info("Current tree is " + cache.printDetails());
 352  8 log.info("nodeD get child E ");
 353  8 nodeE = nodeD.getChild(E);
 354   
 355  8 log.info("Current tree is " + cache.printDetails());
 356   
 357  8 Fqn old_C = new Fqn(C);
 358  8 Fqn old_D = new Fqn(old_C, D);
 359  8 Fqn old_E = new Fqn(old_D, E);
 360   
 361  8 assertNotNull(cache.peek(A, false));
 362  8 assertNotNull(cache.peek(B, false));
 363  8 assertNull(cache.peek(C, false));
 364  8 assertNull(cache.peek(new Fqn(A, C), false));
 365  8 assertNotNull(cache.peek(new Fqn(B, C), false));
 366   
 367  8 assertNotNull(cache.peek(new Fqn(new Fqn(B, C), D), false));
 368  8 assertNotNull(cache.peek(new Fqn(new Fqn(new Fqn(B, C), D), E), false));
 369   
 370    // test data
 371  8 assertEquals(vA, nodeA.get(k));
 372  8 assertEquals(vB, nodeB.get(k));
 373  8 assertEquals(vC, nodeC.get(k));
 374  8 assertEquals(vD, nodeD.get(k));
 375  8 assertEquals(vE, nodeE.get(k));
 376   
 377    // parentage
 378  8 assertEquals(rootNode, nodeA.getParent());
 379  8 assertEquals(rootNode, nodeB.getParent());
 380  8 assertEquals(nodeB, nodeC.getParent());
 381  8 assertEquals(nodeC, nodeD.getParent());
 382  8 assertEquals(nodeD, nodeE.getParent());
 383   
 384  4 if (pasv) cache.evict(Fqn.ROOT, true);
 385   
 386    //now inspect the loader.
 387  8 assertEquals(vA, loader.get(nodeA.getFqn()).get(k));
 388  8 assertEquals(vB, loader.get(nodeB.getFqn()).get(k));
 389  8 assertEquals(vC, loader.get(nodeC.getFqn()).get(k));
 390  8 assertEquals(vD, loader.get(nodeD.getFqn()).get(k));
 391  8 assertEquals(vE, loader.get(nodeE.getFqn()).get(k));
 392   
 393  8 assertNull(loader.get(old_C));
 394  8 assertNull(loader.get(old_D));
 395  8 assertNull(loader.get(old_E));
 396   
 397    }
 398   
 399  1 public void testLocksDeepMove() throws Exception
 400    {
 401  1 nodeA = rootNode.addChild(A);
 402  1 nodeB = nodeA.addChild(B);
 403  1 nodeD = nodeB.addChild(D);
 404  1 nodeC = rootNode.addChild(C);
 405  1 assertEquals(0, cache.getNumberOfLocksHeld());
 406  1 tm.begin();
 407   
 408  1 cache.move(nodeC.getFqn(), nodeB.getFqn());
 409    // nodeC should have a RL, nodeA should have a RL, nodeB should have a WL, nodeD should have a WL
 410   
 411  1 System.out.println("LOCKS: " + cache.printLockInfo());
 412   
 413  1 assertEquals("ROOT should have a RL, nodeC should have a RL, nodeA should have a RL, nodeB should have a WL, nodeD should have a WL", 5, cache.getNumberOfLocksHeld());
 414   
 415   
 416  1 tm.commit();
 417   
 418  1 assertEquals(0, cache.getNumberOfLocksHeld());
 419    }
 420   
 421  1 public void testLocks() throws Exception
 422    {
 423  1 nodeA = rootNode.addChild(A);
 424  1 nodeB = nodeA.addChild(B);
 425  1 nodeC = rootNode.addChild(C);
 426  1 assertEquals(0, cache.getNumberOfLocksHeld());
 427  1 tm.begin();
 428   
 429  1 cache.move(nodeC.getFqn(), nodeB.getFqn());
 430   
 431    // nodeC should have a RL, nodeA should have a RL, nodeB should have a WL
 432   
 433  1 System.out.println("LOCKS: " + cache.printLockInfo());
 434   
 435  1 assertEquals("ROOT should have a RL, nodeC should have a RL, nodeA should have a RL, nodeB should have a WL", 4, cache.getNumberOfLocksHeld());
 436   
 437   
 438  1 tm.commit();
 439   
 440  1 assertEquals(0, cache.getNumberOfLocksHeld());
 441    }
 442   
 443   
 444  0 public void XtestConcurrency() throws InterruptedException
 445    {
 446    // TODO: investigate intermittent failure when in optimistic mode.
 447  0 if (optimistic) return;
 448   
 449  0 final int N = 3;// number of threads
 450  0 final int loops = 1 << 6;// number of loops
 451    // tests a tree structure as such:
 452    // /a
 453    // /b
 454    // /c
 455    // /d
 456    // /e
 457    // /x
 458    // /y
 459   
 460    // N threads constantly move /x and /y around to hang off either /a ~ /e randomly.
 461   
 462  0 final Fqn FQN_A = A, FQN_B = B, FQN_C = C, FQN_D = D, FQN_E = E, FQN_X = Fqn.fromString("/x"), FQN_Y = Fqn.fromString("/y");
 463   
 464    // set up the initial structure.
 465  0 final Node[] NODES = {
 466    rootNode.addChild(FQN_A), rootNode.addChild(FQN_B),
 467    rootNode.addChild(FQN_C), rootNode.addChild(FQN_D), rootNode.addChild(FQN_E)
 468    };
 469   
 470  0 final Node NODE_X = NODES[0].addChild(FQN_X);
 471  0 final Node NODE_Y = NODES[1].addChild(FQN_Y);
 472   
 473  0 Thread[] movers = new Thread[N];
 474  0 final CountDownLatch latch = new CountDownLatch(1);
 475  0 final Random r = new Random();
 476   
 477  0 for (int i = 0; i < N; i++)
 478    {
 479  0 movers[i] = new Thread("Mover-" + i)
 480    {
 481  0 public void run()
 482    {
 483  0 try
 484    {
 485  0 latch.await();
 486    }
 487    catch (InterruptedException e)
 488    {
 489    }
 490   
 491  0 for (int counter = 0; counter < loops; counter++)
 492    {
 493   
 494  0 System.out.println(getName() + ": Attempt " + counter);
 495  0 try
 496    {
 497  0 cache.move(NODE_X.getFqn(), NODES[r.nextInt(NODES.length)].getFqn());
 498    }
 499    catch (NodeNotExistsException e)
 500    {
 501    // this may happen ...
 502    }
 503  0 TestingUtil.sleepRandom(250);
 504  0 try
 505    {
 506  0 cache.move(NODE_Y.getFqn(), NODES[r.nextInt(NODES.length)].getFqn());
 507    }
 508    catch (NodeNotExistsException e)
 509    {
 510    // this may happen ...
 511    }
 512  0 TestingUtil.sleepRandom(250);
 513    }
 514    }
 515    };
 516  0 movers[i].start();
 517    }
 518   
 519  0 latch.countDown();
 520   
 521  0 for (Thread t : movers)
 522    {
 523  0 t.join();
 524    }
 525   
 526  0 assertEquals(0, cache.getNumberOfLocksHeld());
 527  0 boolean found_x = false, found_x_again = false;
 528  0 for (Node n : NODES)
 529    {
 530  0 if (!found_x)
 531    {
 532  0 found_x = n.hasChild(FQN_X);
 533    }
 534    else
 535    {
 536  0 found_x_again = found_x_again || n.hasChild(FQN_X);
 537    }
 538    }
 539  0 boolean found_y = false, found_y_again = false;
 540  0 for (Node n : NODES)
 541    {
 542  0 if (!found_y)
 543    {
 544  0 found_y = n.hasChild(FQN_Y);
 545    }
 546    else
 547    {
 548  0 found_y_again = found_y_again || n.hasChild(FQN_Y);
 549    }
 550    }
 551   
 552  0 assertTrue("Should have found x", found_x);
 553  0 assertTrue("Should have found y", found_y);
 554  0 assertFalse("Should have only found x once", found_x_again);
 555  0 assertFalse("Should have only found y once", found_y_again);
 556    }
 557    }