Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 1,330   Methods: 55
NCLOC: 941   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
TransactionTest.java 60% 92.5% 98.2% 92%
coverage coverage
 1    /*
 2    *
 3    * JBoss, the OpenSource J2EE webOS
 4    *
 5    * Distributable under LGPL license.
 6    * See terms of license at gnu.org.
 7    */
 8   
 9    package org.jboss.cache.transaction;
 10   
 11    import junit.framework.Test;
 12    import junit.framework.TestCase;
 13    import junit.framework.TestSuite;
 14    import org.jboss.cache.CacheException;
 15    import org.jboss.cache.CacheImpl;
 16    import org.jboss.cache.DefaultCacheFactory;
 17    import org.jboss.cache.Fqn;
 18    import org.jboss.cache.Node;
 19    import org.jboss.cache.NodeSPI;
 20    import org.jboss.cache.lock.IsolationLevel;
 21    import org.jboss.cache.lock.NodeLock;
 22   
 23    import javax.naming.Context;
 24    import javax.naming.InitialContext;
 25    import javax.transaction.HeuristicMixedException;
 26    import javax.transaction.HeuristicRollbackException;
 27    import javax.transaction.NotSupportedException;
 28    import javax.transaction.RollbackException;
 29    import javax.transaction.SystemException;
 30    import javax.transaction.Transaction;
 31    import javax.transaction.UserTransaction;
 32    import java.util.HashMap;
 33    import java.util.Map;
 34    import java.util.Properties;
 35    import java.util.Set;
 36   
 37    /**
 38    * Tests transactional access to a local CacheImpl.
 39    * Note: we use DummpyTranasctionManager to replace jta
 40    *
 41    * @version $Id: TransactionTest.java,v 1.31 2007/06/14 15:30:17 msurtani Exp $
 42    */
 43    public class TransactionTest extends TestCase
 44    {
 45    CacheImpl cache = null;
 46    UserTransaction tx = null;
 47    Properties p = null;
 48    String old_factory = null;
 49    final String FACTORY = "org.jboss.cache.transaction.DummyContextFactory";
 50    Exception thread_ex;
 51   
 52   
 53  41 public TransactionTest(String name)
 54    {
 55  41 super(name);
 56    }
 57   
 58  41 public void setUp() throws Exception
 59    {
 60  41 super.setUp();
 61  41 old_factory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
 62  41 System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
 63  41 DummyTransactionManager.getInstance();
 64  41 if (p == null)
 65    {
 66  41 p = new Properties();
 67  41 p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.cache.transaction.DummyContextFactory");
 68    }
 69   
 70  41 tx = (UserTransaction) new InitialContext(p).lookup("UserTransaction");
 71  41 cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(false);
 72  41 cache.getConfiguration().setClusterName("test");
 73  41 cache.getConfiguration().setStateRetrievalTimeout(10000);
 74  41 cache.getConfiguration().setTransactionManagerLookupClass("org.jboss.cache.transaction.DummyTransactionManagerLookup");
 75  41 cache.getConfiguration().setIsolationLevel(IsolationLevel.SERIALIZABLE);
 76  41 cache.getConfiguration().setLockParentForChildInsertRemove(true);// this test case is written to assume this.
 77  41 cache.create();
 78  41 cache.start();
 79  41 thread_ex = null;
 80    }
 81   
 82  41 public void tearDown() throws Exception
 83    {
 84  41 super.tearDown();
 85  41 if (cache != null)
 86    {
 87  41 cache.stop();
 88  41 cache = null;
 89    }
 90   
 91    // BW. kind of a hack to destroy jndi binding and thread local tx before next run.
 92  41 DummyTransactionManager.destroy();
 93  41 if (old_factory != null)
 94    {
 95  40 System.setProperty(Context.INITIAL_CONTEXT_FACTORY, old_factory);
 96  40 old_factory = null;
 97    }
 98   
 99  41 if (tx != null)
 100    {
 101  41 try
 102    {
 103  41 tx.rollback();
 104    }
 105    catch (Throwable t)
 106    {
 107    }
 108  41 tx = null;
 109    }
 110    }
 111   
 112   
 113  1 public void testPutTx() throws Exception
 114    {
 115  1 tx.begin();
 116  1 cache.put("/a/b/c", "age", 38);
 117    // the tx interceptor should know that we're in the same tx.
 118  1 assertEquals(cache.get("/a/b/c", "age"), 38);
 119   
 120  1 cache.put("/a/b/c", "age", 39);
 121  1 tx.commit();
 122   
 123    // This test is done outside the TX, it wouldn't work if someone else
 124    // modified "age". This works because we're the only TX running.
 125  1 assertEquals(cache.get("/a/b/c", "age"), 39);
 126    }
 127   
 128   
 129  1 public void testRollbackTx1()
 130    {
 131  1 try
 132    {
 133  1 tx.begin();
 134  1 cache.put("/a/b/c", "age", 38);
 135  1 cache.put("/a/b/c", "age", 39);
 136  1 tx.rollback();
 137   
 138    // This test is done outside the TX, it wouldn't work if someone else
 139    // modified "age". This works because we're the only TX running.
 140  1 assertNull(cache.get("/a/b/c", "age"));
 141    }
 142    catch (Throwable t)
 143    {
 144  0 t.printStackTrace();
 145  0 fail(t.toString());
 146    }
 147    }
 148   
 149   
 150  1 public void testGetAfterRemovalRollback() throws Exception
 151    {
 152  1 assertEquals(0, cache.getNumberOfLocksHeld());
 153  1 cache.put("/a/b", null);
 154  1 assertEquals(0, cache.getNumberOfLocksHeld());
 155  1 assertTrue(cache.exists("/a/b"));
 156  1 tx.begin();
 157  1 cache.remove("/a/b");
 158  1 assertFalse(cache.exists("/a/b"));
 159  1 tx.rollback();
 160  1 assertTrue(cache.exists("/a/b"));
 161  1 assertEquals(0, cache.getNumberOfLocksHeld());
 162    // new tx in new thread
 163  1 Thread th = new Thread()
 164    {
 165  1 public void run()
 166    {
 167  1 try
 168    {
 169  1 cache.getTransactionManager().begin();
 170  1 assertNotNull(cache.get("/a/b"));
 171  1 cache.getTransactionManager().rollback();
 172    }
 173    catch (Exception e)
 174    {
 175  0 e.printStackTrace();
 176  0 fail("Caught exception");
 177    }
 178    }
 179    };
 180   
 181  1 th.start();
 182  1 th.join();
 183   
 184  1 assertEquals(0, cache.getNumberOfLocksHeld());
 185    }
 186   
 187  1 public void testRollbackTx2()
 188    {
 189  1 try
 190    {
 191  1 tx.begin();
 192  1 cache.put("/a/b/c", "age", 38);
 193  1 cache.remove("/a/b/c", "age");
 194  1 tx.rollback();
 195   
 196    // This test is done outside the TX, it wouldn't work if someone else
 197    // modified "age". This works because we're the only TX running.
 198  1 assertNull(cache.get("/a/b/c", "age"));
 199    }
 200    catch (Throwable t)
 201    {
 202  0 t.printStackTrace();
 203  0 fail(t.toString());
 204    }
 205    }
 206   
 207  1 public void testRollbackTx2a()
 208    {
 209  1 try
 210    {
 211  1 System.out.println("locks " + cache.printLockInfo());
 212  1 cache.put("/a/b/c", "age", 38);
 213  1 System.out.println("locks " + cache.printLockInfo());
 214  1 tx.begin();
 215  1 cache.remove("/a/b/c", "age");
 216  1 tx.rollback();
 217   
 218    // This test is done outside the TX, it wouldn't work if someone else
 219    // modified "age". This works because we're the only TX running.
 220  1 assertEquals(38, cache.get("/a/b/c", "age"));
 221    }
 222    catch (Throwable t)
 223    {
 224  0 t.printStackTrace();
 225  0 fail(t.toString());
 226    }
 227    }
 228   
 229  1 public void testRollbackTx3()
 230    {
 231  1 try
 232    {
 233  1 java.util.Map map1 = new java.util.HashMap();
 234  1 map1.put("age", 38);
 235  1 java.util.Map map2 = new java.util.HashMap();
 236  1 map2.put("age", 39);
 237  1 tx.begin();
 238  1 cache.put("/a/b/c", map1);
 239  1 cache.put("/a/b/c", map2);
 240  1 tx.rollback();
 241   
 242    // This test is done outside the TX, it wouldn't work if someone else
 243    // modified "age". This works because we're the only TX running.
 244  1 assertNull(cache.get("/a/b/c", "age"));
 245    }
 246    catch (Throwable t)
 247    {
 248  0 t.printStackTrace();
 249  0 fail(t.toString());
 250    }
 251    }
 252   
 253   
 254  1 public void testRollbackTx4()
 255    {
 256  1 try
 257    {
 258  1 Map map = new HashMap();
 259  1 map.put("age", 38);
 260  1 tx.begin();
 261  1 cache.put("/a/b/c", map);
 262  1 cache.remove("/a/b/c");
 263  1 tx.rollback();
 264   
 265    // This test is done outside the TX, it wouldn't work if someone else
 266    // modified "age". This works because we're the only TX running.
 267  1 assertNull(cache.get("/a/b/c", "age"));
 268    }
 269    catch (Throwable t)
 270    {
 271  0 t.printStackTrace();
 272  0 fail(t.toString());
 273    }
 274    }
 275   
 276  1 public void testNodeCreationRollback()
 277    {
 278  1 try
 279    {
 280  1 tx.begin();
 281  1 System.out.println("initial state:\n" + cache);
 282  1 cache.put("/bela/ban", "key", "value");
 283  1 System.out.println("after put():\n" + cache);
 284  1 tx.rollback();
 285  1 System.out.println("after rollback():\n" + cache);
 286   
 287  1 assertNull("node should be not existent", cache.get("/bela/ban"));
 288    }
 289    catch (Throwable t)
 290    {
 291  0 t.printStackTrace();
 292  0 fail(t.toString());
 293    }
 294    }
 295   
 296  1 public void testNodeCreationRollback2()
 297    {
 298  1 try
 299    {
 300  1 cache.put("/bela/ban", null);
 301  1 tx.begin();
 302  1 cache.put("/bela/ban/michelle", null);
 303  1 tx.rollback();
 304  1 assertNotNull("node should be not null", cache.get("/bela/ban"));
 305  1 assertNull("node should be not existent", cache.get("/bela/ban/michelle"));
 306    }
 307    catch (Throwable t)
 308    {
 309  0 t.printStackTrace();
 310  0 fail(t.toString());
 311    }
 312    }
 313   
 314  1 public void testNodeDeletionRollback()
 315    {
 316  1 try
 317    {
 318  1 cache.put("/a/b/c", null);
 319  1 tx.begin();
 320  1 cache.remove("/a/b/c");
 321  1 assertNull(cache.get("/a/b/c"));
 322  1 cache.remove("/a/b");
 323  1 assertNull(cache.get("/a/b"));
 324  1 cache.remove("/a");
 325  1 assertNull(cache.get("/a"));
 326  1 tx.rollback();
 327  1 assertNotNull(cache.get("/a/b/c"));
 328  1 assertNotNull(cache.get("/a/b"));
 329  1 assertNotNull(cache.get("/a"));
 330    }
 331    catch (Throwable t)
 332    {
 333  0 t.printStackTrace();
 334  0 fail(t.toString());
 335    }
 336    }
 337   
 338  1 public void testNodeDeletionRollback2() throws Exception
 339    {
 340  1 cache.put("/a/b/c", null);
 341  1 cache.put("/a/b/c1", null);
 342  1 cache.put("/a/b/c2", null);
 343  1 tx.begin();
 344  1 cache.remove("/a");
 345  1 assertNull(cache.get("/a/b/c"));
 346  1 assertNull(cache.get("/a/b/c1"));
 347  1 assertNull(cache.get("/a/b/c2"));
 348  1 assertNull(cache.get("/a/b"));
 349  1 assertNull(cache.get("/a"));
 350  1 Set children = cache.getChildrenNames("/a/b");
 351  1 assertTrue(children.isEmpty());
 352  1 children = cache.getChildrenNames("/a");
 353  1 assertTrue(children.isEmpty());
 354  1 tx.rollback();
 355  1 assertNotNull(cache.get("/a"));
 356  1 assertNotNull(cache.get("/a/b"));
 357  1 assertNotNull(cache.get("/a/b/c"));
 358  1 assertNotNull(cache.get("/a/b/c1"));
 359  1 assertNotNull(cache.get("/a/b/c2"));
 360  1 children = cache.getChildrenNames("/a/b");
 361  1 assertEquals(3, children.size());
 362    }
 363   
 364   
 365  1 public void testNodeCreation() throws Exception
 366    {
 367  1 GlobalTransaction gtx;
 368  1 cache.put("/a/b", null);
 369  1 tx.begin();
 370  1 gtx = cache.getCurrentTransaction();
 371  1 cache.put("/a/b/c", null);
 372  1 assertLocked(gtx, "/a", false);
 373  1 assertLocked(gtx, "/a/b", true);
 374  1 assertLocked(gtx, "/a/b/c", true);
 375  1 System.out.println("locks: " + cache.printLockInfo());
 376    }
 377   
 378   
 379  1 public void testNodeCreation2() throws Exception
 380    {
 381  1 GlobalTransaction gtx;
 382  1 tx.begin();
 383  1 gtx = cache.getCurrentTransaction();
 384  1 cache.put("/a/b/c", null);
 385  1 assertLocked(gtx, "/a", true);
 386  1 assertLocked(gtx, "/a/b", true);
 387  1 assertLocked(gtx, "/a/b/c", true);
 388  1 System.out.println("locks: " + cache.printLockInfo());
 389    }
 390   
 391   
 392  1 public void testNodeRemoval()
 393    {
 394  1 GlobalTransaction gtx;
 395  1 try
 396    {
 397  1 cache.put("/a/b/c", null);
 398  1 tx.begin();
 399  1 gtx = cache.getCurrentTransaction();
 400  1 cache.remove("/a/b/c");// need to remove the node, not just the data in the node.
 401  1 System.out.println("Locks: " + cache.printLockInfo());
 402  1 assertLocked(gtx, "/a", false);
 403  1 assertLocked(gtx, "/a/b", true);
 404  1 assertLocked(gtx, "/a/b/c", true);
 405  1 System.out.println("locks: " + cache.printLockInfo());
 406    }
 407    catch (Throwable t)
 408    {
 409  0 t.printStackTrace();
 410  0 fail(t.toString());
 411    }
 412    }
 413   
 414   
 415  1 public void testNodeRemoval2()
 416    {
 417  1 GlobalTransaction gtx;
 418  1 try
 419    {
 420  1 cache.put("/a/b/c", null);
 421  1 tx.begin();
 422  1 gtx = cache.getCurrentTransaction();
 423  1 cache.remove("/a/b");// need to remove the node, not just the data in the node.
 424  1 assertLocked(gtx, "/a", true);
 425  1 assertLocked(gtx, "/a/b", true);
 426  1 assertLocked(gtx, "/a/b/c", true);
 427  1 System.out.println("locks: " + cache.printLockInfo());
 428    }
 429    catch (Throwable t)
 430    {
 431  0 t.printStackTrace();
 432  0 fail(t.toString());
 433    }
 434    }
 435   
 436  1 public void testIntermediateNodeCreationOnWrite() throws Exception
 437    {
 438  1 cache.put("/a", null);
 439  1 tx.begin();
 440  1 cache.put("/a/b/c", null);
 441    // expecting WLs on /a, /a/b and /a/b/c.
 442  1 GlobalTransaction gtx = cache.getCurrentTransaction();
 443  1 assertLocked(gtx, "/a", true);
 444  1 assertLocked(gtx, "/a/b", true);
 445  1 assertLocked(gtx, "/a/b/c", true);
 446  1 tx.rollback();
 447   
 448    }
 449   
 450  1 public void testIntermediateNodeCreationOnRead() throws Exception
 451    {
 452  1 cache.put("/a", null);
 453  1 tx.begin();
 454  1 cache.get("/a/b/c");
 455   
 456    // expecting RLs on /, /a
 457    // /a/b, /a/b/c should NOT be created!
 458  1 GlobalTransaction gtx = cache.getCurrentTransaction();
 459  1 assertLocked(gtx, "/", false);
 460  1 assertLocked(gtx, "/a", false);
 461  1 assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b"), true));
 462  1 assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c"), true));
 463  1 tx.rollback();
 464  1 assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b"), true));
 465  1 assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c"), true));
 466   
 467    }
 468   
 469   
 470  1 public void testIntermediateNodeCreationOnRemove() throws Exception
 471    {
 472  1 cache.put("/a", null);
 473  1 tx.begin();
 474  1 cache.remove("/a/b/c");
 475   
 476    // expecting RLs on /, /a
 477    // /a/b, /a/b/c should NOT be created!
 478  1 GlobalTransaction gtx = cache.getCurrentTransaction();
 479  1 assertLocked(gtx, "/", false);
 480  1 assertLocked(gtx, "/a", false);
 481  1 assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b"), true));
 482  1 assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c"), true));
 483  1 tx.rollback();
 484  1 assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b"), true));
 485  1 assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c"), true));
 486   
 487    }
 488   
 489   
 490  1 public void testNodeDeletionRollback3() throws Exception
 491    {
 492  1 GlobalTransaction gtx;
 493  1 cache.put("/a/b/c1", null);
 494   
 495  1 tx.begin();
 496  1 gtx = cache.getCurrentTransaction();
 497  1 cache.put("/a/b/c1", null);
 498  1 assertLocked(gtx, "/a", false);
 499  1 assertLocked(gtx, "/a/b", false);
 500  1 assertLocked(gtx, "/a/b/c1", true);
 501   
 502  1 cache.put("/a/b/c2", null);
 503  1 assertLocked(gtx, "/a/b", true);
 504  1 assertLocked(gtx, "/a/b/c2", true);
 505   
 506  1 cache.put("/a/b/c3", null);
 507  1 cache.put("/a/b/c1/one", null);
 508  1 assertLocked(gtx, "/a/b/c1", true);
 509  1 assertLocked(gtx, "/a/b/c1/one", true);
 510   
 511  1 cache.put("/a/b/c1/two", null);
 512  1 cache.put("/a/b/c1/one/1", null);
 513  1 assertLocked(gtx, "/a/b/c1", true);
 514  1 assertLocked(gtx, "/a/b/c1/one", true);
 515  1 assertLocked(gtx, "/a/b/c1/one/1", true);
 516   
 517  1 cache.put("/a/b/c1/two/2/3/4", null);
 518  1 assertLocked(gtx, "/a/b/c1", true);
 519  1 assertLocked(gtx, "/a/b/c1/two", true);
 520  1 assertLocked(gtx, "/a/b/c1/two/2", true);
 521  1 assertLocked(gtx, "/a/b/c1/two/2/3", true);
 522  1 assertLocked(gtx, "/a/b/c1/two/2/3/4", true);
 523   
 524  1 System.out.println("locks: " + cache.printLockInfo());
 525   
 526  1 cache.remove("/a/b");
 527  1 tx.rollback();
 528  1 assertTrue(cache.getChildrenNames("/a/b/c1").isEmpty());
 529  1 Set cn = cache.getChildrenNames("/a/b");
 530  1 assertEquals(1, cn.size());
 531  1 assertEquals("c1", cn.iterator().next());
 532    }
 533   
 534  1 public void testDoubleLocks() throws Exception
 535    {
 536  1 tx.begin();
 537  1 GlobalTransaction gtx = cache.getCurrentTransaction();
 538  1 cache.put("/a/b/c", null);
 539  1 cache.put("/a/b/c", null);
 540   
 541  1 NodeSPI n = (NodeSPI) cache.get("/a");
 542  1 NodeLock lock = n.getLock();
 543  1 int num = lock.getReaderOwners().size();
 544  1 assertEquals(0, num);
 545    // make sure this is write locked.
 546  1 assertLocked(gtx, "/a", true);
 547   
 548  1 n = (NodeSPI) cache.get("/a/b");
 549  1 lock = n.getLock();
 550  1 num = lock.getReaderOwners().size();
 551  1 assertEquals(0, num);
 552    // make sure this is write locked.
 553  1 assertLocked(gtx, "/a/b", true);
 554   
 555  1 n = (NodeSPI) cache.get("/a/b/c");
 556  1 lock = n.getLock();
 557  1 num = lock.getReaderOwners().size();
 558  1 assertEquals(0, num);
 559    // make sure this is write locked.
 560  1 assertLocked(gtx, "/a/b/c", true);
 561   
 562  1 tx.rollback();
 563  1 assertEquals(0, cache.getNumberOfLocksHeld());
 564    }
 565   
 566  37 private void assertLocked(Object owner, String fqn, boolean write_locked) throws Exception
 567    {
 568  37 NodeSPI n = cache.peek(Fqn.fromString(fqn), true);
 569  37 NodeLock lock = n.getLock();
 570  37 if (owner == null)
 571    {
 572  0 owner = Thread.currentThread();
 573    }
 574  37 assertTrue("node " + fqn + " is not locked", lock.isLocked());
 575  37 if (write_locked)
 576    {
 577  29 assertTrue("node " + fqn + " is not write-locked" + (lock.isReadLocked() ? " but is read-locked instead!" : "!"), lock.isWriteLocked());
 578    }
 579    else
 580    {
 581  8 assertTrue("node " + fqn + " is not read-locked" + (lock.isWriteLocked() ? " but is write-locked instead!" : "!"), lock.isReadLocked());
 582    }
 583  37 assertTrue("owner " + owner + "is not owner", lock.isOwner(owner));
 584    }
 585   
 586  1 public void testConcurrentNodeAccessOnRemovalWithTx() throws Exception
 587    {
 588  1 cache.put("/a/b/c", null);
 589  1 tx.begin();
 590  1 cache.remove("/a/b/c");
 591    // this node should now be locked.
 592  1 Transaction t = cache.getTransactionManager().suspend();
 593  1 Transaction t2 = null;
 594  1 try
 595    {
 596  1 System.out.println(cache.printLockInfo());
 597    // start a new tx
 598  1 cache.getTransactionManager().begin();
 599  1 t2 = cache.getTransactionManager().getTransaction();
 600  1 cache.get("/a/b/c");// should fail
 601  0 t2.commit();
 602  0 fail("Should not be able to get a hold of /a/b/c until the deleting tx completes");
 603    }
 604    catch (Exception e)
 605    {
 606    // expected
 607  1 t2.commit();
 608    }
 609   
 610  1 cache.getTransactionManager().resume(t);
 611  1 tx.rollback();
 612   
 613  1 assertNotNull(cache.get("/a/b/c"));
 614  1 assertEquals(0, cache.getNumberOfLocksHeld());
 615    }
 616   
 617  1 public void testConcurrentNodeAccessOnRemovalWithoutTx() throws Exception
 618    {
 619  1 cache.put("/a/b/c", null);
 620  1 tx.begin();
 621  1 cache.remove("/a/b/c");
 622    // this node should now be locked.
 623  1 Transaction t = cache.getTransactionManager().suspend();
 624  1 Thread th = new Thread()
 625    {
 626  1 public void run()
 627    {
 628  1 try
 629    {
 630  1 System.out.println(cache.printLockInfo());
 631  1 cache.get("/a/b/c");// should fail
 632   
 633  0 fail("Should not be able to get a hold of /a/b/c until the deleting tx completes");
 634    }
 635    catch (Exception e)
 636    {
 637    // expected
 638    }
 639    }
 640    };
 641   
 642  1 th.start();
 643  1 th.join();
 644   
 645  1 cache.getTransactionManager().resume(t);
 646  1 tx.rollback();
 647   
 648  1 assertNotNull(cache.get("/a/b/c"));
 649  1 assertEquals(0, cache.getNumberOfLocksHeld());
 650    }
 651   
 652   
 653  1 public void testRemove() throws CacheException, SystemException, NotSupportedException, HeuristicMixedException, HeuristicRollbackException, RollbackException
 654    {
 655  1 cache.put("/a/b/c", null);
 656  1 cache.put("/a/b/c/1", null);
 657  1 cache.put("/a/b/c/2", null);
 658  1 cache.put("/a/b/c/3", null);
 659  1 cache.put("/a/b/c/3/a/b/c", null);
 660   
 661  1 assertEquals(0, cache.getNumberOfLocksHeld());
 662  1 assertEquals(0, cache.getLockTable().size());
 663   
 664  1 tx.begin();
 665  1 cache.remove("/a/b/c");
 666  1 System.out.println("locks held (after removing /a/b/c): \n" + cache.printLockInfo());
 667    // this used to test for 2 locks held. After the fixes for JBCACHE-875 however, 2 more locks are acquired - for the root node as well as the deleted node.
 668    // and since we would lock all children of the deleted node as well, we have 10 locks here.
 669  1 assertEquals(10, cache.getNumberOfLocksHeld());
 670  1 tx.commit();
 671  1 System.out.println("locks held (after committing /a/b/c): \n" + cache.printLockInfo());
 672  1 assertEquals(0, cache.getNumberOfLocksHeld());
 673    }
 674   
 675   
 676  1 public void testRemoveAndRollback() throws CacheException, SystemException, NotSupportedException, HeuristicMixedException, HeuristicRollbackException, RollbackException
 677    {
 678  1 cache.put("/a/b/c", null);
 679  1 cache.put("/a/b/c/1", null);
 680  1 cache.put("/a/b/c/2", null);
 681  1 cache.put("/a/b/c/3", null);
 682  1 cache.put("/a/b/c/3/a/b/c", null);
 683   
 684  1 assertEquals(0, cache.getNumberOfLocksHeld());
 685  1 assertEquals(0, cache.getLockTable().size());
 686   
 687  1 tx.begin();
 688  1 System.out.println("locks held (before removing /a/b/c): \n" + cache.printLockInfo());
 689  1 cache.remove("/a/b/c");
 690  1 System.out.println("locks held (after removing /a/b/c): \n" + cache.printLockInfo());
 691  1 assertEquals(10, cache.getNumberOfLocksHeld());
 692  1 tx.rollback();
 693  1 System.out.println("locks held (after rollback): \n" + cache.printLockInfo());
 694  1 assertEquals(0, cache.getNumberOfLocksHeld());
 695   
 696  1 assertTrue(cache.exists("/a/b/c"));
 697  1 assertTrue(cache.exists("/a/b/c/1"));
 698  1 assertTrue(cache.exists("/a/b/c/2"));
 699  1 assertTrue(cache.exists("/a/b/c/3"));
 700  1 assertTrue(cache.exists("/a/b/c/3/a"));
 701  1 assertTrue(cache.exists("/a/b/c/3/a/b"));
 702  1 assertTrue(cache.exists("/a/b/c/3/a/b/c"));
 703    }
 704   
 705   
 706  1 public void testRemoveKeyRollback() throws CacheException, SystemException, NotSupportedException
 707    {
 708  1 cache.put("/bela/ban", "name", "Bela");
 709  1 tx.begin();
 710  1 cache.remove("/bela/ban", "name");
 711  1 assertNull(cache.get("/bela/ban", "name"));
 712  1 tx.rollback();
 713  1 assertEquals("Bela", cache.get("/bela/ban", "name"));
 714    }
 715   
 716   
 717  1 public void testRemoveKeyRollback2()
 718    {
 719  1 try
 720    {
 721  1 Map m = new HashMap();
 722  1 m.put("name", "Bela");
 723  1 m.put("id", 322649);
 724  1 cache.put("/bela/ban", m);
 725  1 tx.begin();
 726  1 cache.remove("/bela/ban", "name");
 727  1 assertNull(cache.get("/bela/ban", "name"));
 728  1 tx.rollback();
 729  1 assertEquals("Bela", cache.get("/bela/ban", "name"));
 730    }
 731    catch (Throwable t)
 732    {
 733  0 t.printStackTrace();
 734  0 fail(t.toString());
 735    }
 736    }
 737   
 738  1 public void testRemoveKeyRollback3()
 739    {
 740  1 try
 741    {
 742  1 cache.put("/bela/ban", "name", "Bela");
 743  1 tx.begin();
 744  1 cache.put("/bela/ban", "name", "Michelle");
 745  1 cache.remove("/bela/ban", "name");
 746  1 assertNull(cache.get("/bela/ban", "name"));
 747  1 tx.rollback();
 748  1 assertEquals("Bela", cache.get("/bela/ban", "name"));
 749    }
 750    catch (Throwable t)
 751    {
 752  0 t.printStackTrace();
 753  0 fail(t.toString());
 754    }
 755    }
 756   
 757   
 758  1 public void testDoubleRemovalOfSameData()
 759    {
 760  1 try
 761    {
 762  1 tx.begin();
 763  1 cache.put("/foo/1", "item", 1);
 764  1 assertEquals(cache.get("/foo/1", "item"), 1);
 765  1 cache.remove("/foo/1");
 766  1 assertNull(cache.get("/foo/1", "item"));
 767  1 cache.remove("/foo/1");
 768  1 assertNull(cache.get("/foo/1", "item"));
 769  1 tx.rollback();
 770  1 assertFalse(cache.exists("/foo/1"));
 771  1 assertNull(cache.get("/foo/1", "item"));
 772    }
 773    catch (Throwable t)
 774    {
 775  0 t.printStackTrace();
 776  0 fail(t.toString());
 777    }
 778    }
 779   
 780    /**
 781    * put(Fqn, Map) with a previous null map
 782    */
 783  1 public void testPutDataRollback1()
 784    {
 785  1 try
 786    {
 787  1 cache.put("/bela/ban", null);// create a node /bela/ban with a null map
 788  1 tx.begin();
 789  1 Map m = new HashMap();
 790  1 m.put("name", "Bela");
 791  1 m.put("id", 322649);
 792  1 cache.put("/bela/ban", m);
 793  1 tx.rollback();
 794   
 795  1 Node n = cache.get("/bela/ban");
 796  0 if (n.getData() == null) return;
 797  1 assertEquals("map should be empty", 0, n.getData().size());
 798    }
 799    catch (Throwable t)
 800    {
 801  0 t.printStackTrace();
 802  0 fail(t.toString());
 803    }
 804    }
 805   
 806    /**
 807    * put(Fqn, Map) with a previous non-null map
 808    */
 809  1 public void testputDataRollback2()
 810    {
 811  1 Map m1, m2;
 812  1 m1 = new HashMap();
 813  1 m1.put("name", "Bela");
 814  1 m1.put("id", 322649);
 815  1 m2 = new HashMap();
 816  1 m2.put("other", "bla");
 817  1 m2.put("name", "Michelle");
 818   
 819  1 try
 820    {
 821  1 cache.put("/bela/ban", m1);
 822  1 tx.begin();
 823   
 824  1 cache.put("/bela/ban", m2);
 825  1 Map tmp = cache.get("/bela/ban").getData();
 826  1 assertEquals(3, tmp.size());
 827  1 assertEquals("Michelle", tmp.get("name"));
 828  1 assertEquals(tmp.get("id"), 322649);
 829  1 assertEquals("bla", tmp.get("other"));
 830  1 tx.rollback();
 831   
 832  1 tmp = cache.get("/bela/ban").getData();
 833  1 assertEquals(2, tmp.size());
 834  1 assertEquals("Bela", tmp.get("name"));
 835  1 assertEquals(tmp.get("id"), 322649);
 836    }
 837    catch (Throwable t)
 838    {
 839  0 t.printStackTrace();
 840  0 fail(t.toString());
 841    }
 842    }
 843   
 844   
 845  1 public void testPutRollback()
 846    {
 847  1 try
 848    {
 849  1 cache.put("/bela/ban", null);// /bela/ban needs to exist
 850  1 tx.begin();
 851  1 cache.put("/bela/ban", "name", "Bela");
 852  1 assertEquals("Bela", cache.get("/bela/ban", "name"));
 853  1 tx.rollback();
 854  1 assertNull(cache.get("/bela/ban", "name"));
 855    }
 856    catch (Throwable t)
 857    {
 858  0 t.printStackTrace();
 859  0 fail(t.toString());
 860    }
 861    }
 862   
 863   
 864  1 public void testPutRollback2()
 865    {
 866  1 try
 867    {
 868  1 cache.put("/bela/ban", "name", "Bela");// /bela/ban needs to exist
 869  1 tx.begin();
 870  1 cache.put("/bela/ban", "name", "Michelle");
 871  1 assertEquals("Michelle", cache.get("/bela/ban", "name"));
 872  1 tx.rollback();
 873  1 assertEquals("Bela", cache.get("/bela/ban", "name"));
 874    }
 875    catch (Throwable t)
 876    {
 877  0 t.printStackTrace();
 878  0 fail(t.toString());
 879    }
 880    }
 881   
 882   
 883  1 public void testSimpleRollbackTransactions() throws Exception
 884    {
 885  1 final Fqn FQN = Fqn.fromString("/a/b/c");
 886  1 tx.begin();
 887  1 cache.put(FQN, "entry", "commit");
 888  1 tx.commit();
 889   
 890  1 tx.begin();
 891  1 cache.put(FQN, "entry", "rollback");
 892  1 cache.remove(FQN);
 893  1 tx.rollback();
 894  1 assertEquals("Node should keep the commited value", "commit", cache.get(FQN).get("entry"));
 895   
 896  1 tx.begin();
 897  1 cache.remove(FQN);
 898  1 cache.put(FQN, "entry", "rollback");
 899  1 tx.rollback();
 900  1 assertEquals("Node should keep the commited value", "commit", cache.get(FQN).get("entry"));// THIS FAILS
 901    }
 902   
 903   
 904  2 private Transaction startTransaction() throws Exception
 905    {
 906  2 DummyTransactionManager mgr = DummyTransactionManager.getInstance();
 907  2 mgr.begin();
 908  2 return mgr.getTransaction();
 909    }
 910   
 911   
 912  1 public void testConcurrentReadAndWriteAccess() throws Exception
 913    {
 914  1 cache.stop();
 915  1 cache.getConfiguration().setIsolationLevel(IsolationLevel.REPEATABLE_READ);
 916  1 cache.start();
 917   
 918  1 cache.put("/1/2/3/4", "foo", "bar");// no TX, no locks held after put() returns
 919   
 920   
 921    class Reader extends Thread
 922    {
 923    Transaction thread_tx;
 924   
 925  1 public Reader()
 926    {
 927  1 super("Reader");
 928    }
 929   
 930  1 public void run()
 931    {
 932  1 try
 933    {
 934  1 thread_tx = startTransaction();
 935  1 log("acquiring RL");
 936  1 cache.get("/1/2/3", "foo");// acquires RLs on all 3 nodes
 937  1 log("RL acquired successfully");
 938  1 sleep(2000);
 939  1 log("committing TX");
 940  1 thread_tx.commit();// releases RLs
 941  1 log("committed TX");
 942    }
 943    catch (Exception e)
 944    {
 945  0 thread_ex = e;
 946    }
 947    }
 948    }
 949   
 950    class Writer extends Thread
 951    {
 952    Transaction thread_tx;
 953   
 954  1 public Writer()
 955    {
 956  1 super("Writer");
 957    }
 958   
 959  1 public void run()
 960    {
 961  1 try
 962    {
 963  1 sleep(500);// give the Reader a chance to acquire the RLs
 964  1 thread_tx = startTransaction();
 965  1 log("acquiring WL");
 966  1 cache.put("/1", "foo", "bar2");// needs to acquired a WL on /1
 967  1 log("acquired WL successfully");
 968  1 log("committing TX");
 969  1 thread_tx.commit();
 970  1 log("committed TX");
 971    }
 972    catch (Exception e)
 973    {
 974  0 thread_ex = e;
 975    }
 976    }
 977    }
 978   
 979  1 Reader reader = new Reader();
 980  1 Writer writer = new Writer();
 981  1 reader.start();
 982  1 writer.start();
 983  1 reader.join();
 984  1 writer.join();
 985  1 if (thread_ex != null)
 986    {
 987  0 throw thread_ex;
 988    }
 989    }
 990   
 991  1 public void testRemoveAndGetInTx() throws Exception
 992    {
 993  1 Fqn A_B = Fqn.fromString("/a/b");
 994  1 Fqn A = Fqn.fromString("/a");
 995   
 996  1 cache.put(A_B, "k", "v");
 997   
 998  1 assertTrue(cache.exists(A_B));
 999  1 assertTrue(cache.exists(A));
 1000   
 1001  1 cache.getTransactionManager().begin();
 1002  1 cache.remove(A);
 1003  1 cache.get(A_B, "k");
 1004  1 cache.getTransactionManager().commit();
 1005    }
 1006   
 1007  1 public void testRemoveAndPutInTx() throws Exception
 1008    {
 1009  1 Fqn A_B = Fqn.fromString("/a/b");
 1010  1 Fqn A = Fqn.fromString("/a");
 1011   
 1012  1 cache.put(A_B, "k", "v");
 1013   
 1014  1 assertTrue(cache.exists(A_B));
 1015  1 assertTrue(cache.exists(A));
 1016   
 1017  1 cache.getTransactionManager().begin();
 1018  1 cache.remove(A_B);
 1019  1 cache.put(A_B, "k", "v2");
 1020  1 cache.getTransactionManager().commit();
 1021   
 1022  1 assertTrue(cache.exists(A_B));
 1023  1 assertTrue(cache.exists(A));
 1024   
 1025  1 assertEquals("v2", cache.get(A_B, "k"));
 1026    }
 1027   
 1028  1 public void testRemoveParentAndPutInTx() throws Exception
 1029    {
 1030  1 Fqn A_B = Fqn.fromString("/a/b");
 1031  1 Fqn A = Fqn.fromString("/a");
 1032   
 1033  1 cache.put(A_B, "k", "v");
 1034   
 1035  1 assertTrue(cache.exists(A_B));
 1036  1 assertTrue(cache.exists(A));
 1037   
 1038  1 cache.getTransactionManager().begin();
 1039  1 cache.remove(A);
 1040  1 cache.put(A_B, "k", "v2");
 1041  1 cache.getTransactionManager().commit();
 1042   
 1043  1 assertTrue(cache.exists(A_B));
 1044  1 assertTrue(cache.exists(A));
 1045   
 1046  1 assertEquals("v2", cache.get(A_B, "k"));
 1047    }
 1048   
 1049  1 public void testRemoveGrandParentAndPutInTx() throws Exception
 1050    {
 1051  1 Fqn A_B_C = Fqn.fromString("/a/b/c");
 1052  1 Fqn A = Fqn.fromString("/a");
 1053   
 1054  1 cache.put(A_B_C, "k", "v");
 1055   
 1056  1 assertTrue(cache.exists(A_B_C));
 1057  1 assertTrue(cache.exists(A));
 1058   
 1059  1 cache.getTransactionManager().begin();
 1060  1 cache.remove(A);
 1061  1 cache.put(A_B_C, "k", "v2");
 1062  1 cache.getTransactionManager().commit();
 1063   
 1064  1 assertTrue(cache.exists(A_B_C));
 1065  1 assertTrue(cache.exists(A));
 1066   
 1067  1 assertEquals("v2", cache.get(A_B_C, "k"));
 1068    }
 1069   
 1070   
 1071  1 public void testRootNodeRemoval() throws Exception
 1072    {
 1073  1 Fqn root = Fqn.ROOT;
 1074  1 Fqn fqn = new Fqn(1);
 1075    //put first time
 1076  1 tx.begin();
 1077  1 this.cache.put(fqn, "k", "v");
 1078  1 tx.commit();
 1079   
 1080    //get works fine
 1081  1 tx.begin();
 1082  1 assertEquals("v", this.cache.get(fqn, "k"));
 1083  1 tx.commit();
 1084   
 1085    //remove all
 1086  1 tx.begin();
 1087  1 this.cache.remove(root);
 1088  1 tx.commit();
 1089   
 1090    //get returns null - ok
 1091    //put - endless loop
 1092  1 tx.begin();
 1093  1 assertNull(this.cache.get(fqn, "k"));
 1094  1 this.cache.put(fqn, "k", "v");
 1095  1 tx.commit();
 1096    }
 1097   
 1098  1 public void testNodeAdditionAfterRemoval() throws Exception
 1099    {
 1100  1 Fqn fqn = Fqn.fromString("/1/2/3/4");
 1101    //put first time
 1102  1 tx.begin();
 1103  1 this.cache.put(fqn, "k", "v");
 1104  1 tx.commit();
 1105   
 1106    //get works fine
 1107  1 tx.begin();
 1108  1 assertEquals("v", this.cache.get(fqn, "k"));
 1109  1 tx.commit();
 1110   
 1111    //remove all
 1112  1 tx.begin();
 1113  1 this.cache.remove(Fqn.ROOT);
 1114  1 tx.commit();
 1115   
 1116    //get returns null - ok
 1117    //put - endless loop
 1118  1 tx.begin();
 1119  1 assertNull(this.cache.get(fqn, "k"));
 1120  1 this.cache.put(fqn, "k", "v");
 1121  1 tx.commit();
 1122    }
 1123   
 1124   
 1125  1 public void testRootNodeRemovalRollback() throws Exception
 1126    {
 1127   
 1128  1 Fqn root = Fqn.ROOT;
 1129  1 Fqn fqn = new Fqn(root, 1);
 1130    //put first time
 1131  1 tx.begin();
 1132  1 this.cache.put(fqn, "k", "v");
 1133  1 tx.commit();
 1134   
 1135    //get works fine
 1136  1 tx.begin();
 1137  1 assertEquals("v", this.cache.get(fqn, "k"));
 1138  1 tx.commit();
 1139   
 1140    //remove all
 1141  1 tx.begin();
 1142  1 this.cache.remove(root);
 1143  1 tx.rollback();
 1144   
 1145  1 assertEquals("v", this.cache.get(fqn, "k"));
 1146    }
 1147   
 1148   
 1149    /* public void testConcurrentReadAccess() throws Exception {
 1150    cache.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
 1151    cache.setUseMbean(false);
 1152   
 1153    cache.put("/1/2/3/4", "foo", "bar"); // no TX, no locks held after put() returns
 1154   
 1155   
 1156    class Reader extends Thread {
 1157    Transaction thread_tx;
 1158   
 1159    public Reader(String name) {
 1160    super(name);
 1161    }
 1162   
 1163    public void run() {
 1164    try {
 1165    thread_tx=startTransaction();
 1166    log("acquiring RL");
 1167    cache.get("/1/2/3", "foo"); // acquires RLs on all 3 nodes
 1168    log("RL acquired successfully");
 1169    sleep(200000);
 1170    log("committing TX");
 1171    thread_tx.commit(); // releases RLs
 1172    log("committed TX");
 1173    }
 1174    catch(Exception e) {
 1175    thread_ex=e;
 1176    }
 1177    }
 1178    }
 1179   
 1180   
 1181    Reader reader=new Reader("R1");
 1182    Reader reader2=new Reader("R2");
 1183    reader.start();
 1184    reader2.start();
 1185    reader.join();
 1186    reader2.join();
 1187    if(thread_ex != null)
 1188    throw thread_ex;
 1189    }
 1190   
 1191    */
 1192  8 private static void log(String msg)
 1193    {
 1194  8 System.out.println(Thread.currentThread().getName() + ": " + msg);
 1195    }
 1196   
 1197    // public void testRaceConditionOnNotInCacheCondition() throws Exception {
 1198    // cache.setIsolationLevel(IsolationLevel.SERIALIZABLE);
 1199    //
 1200    // tx.begin();
 1201    // // we now read the null entry, and decide that we need to go do something.
 1202    //
 1203    // Object cachedObject=cache.get("/SecurityInfo/", Integer.toString(23));
 1204    // assertNull(cachedObject); // we expect this in this test
 1205    //
 1206    // /**
 1207    // * now start another Thread to go do the same action, looking for the value, but it SHOULD
 1208    // * see the result of the main thread put once it commits.
 1209    // */
 1210    // Thread thread=new Thread(new Runnable() {
 1211    // UserTransaction tx2=(UserTransaction)new InitialContext(p).lookup("UserTransaction");
 1212    // public void run() {
 1213    // try {
 1214    // tx2.begin();
 1215    // log("OtherThread: inspecting the cache");
 1216    // Object cachedObject=cache.get("/SecurityInfo", Integer.toString(23));
 1217    //
 1218    // log("OtherThread: read from cache: " + cachedObject);
 1219    // Thread.sleep(3000);
 1220    //
 1221    // cachedObject=cache.get("/SecurityInfo", Integer.toString(23));
 1222    // log("OtherThread: read(second time) from cache:" + cachedObject);
 1223    //
 1224    // /**
 1225    // * This should really fail because the other thread should actually have put something else there.
 1226    // */
 1227    // cache.put("/SecurityInfo", Integer.toString(23), "HelloWorldDIRTY!");
 1228    //
 1229    // log("OtherThread: Has put something in the cache tha shouldn't be there");
 1230    // }
 1231    // catch(Exception e) {
 1232    // e.printStackTrace();
 1233    // }
 1234    // finally {
 1235    // if(tx2 != null)
 1236    // try {tx2.commit();} catch(Exception e) {e.printStackTrace();}
 1237    // }
 1238    // log("OthreThread: exiting");
 1239    //
 1240    // }
 1241    // });
 1242    //
 1243    // thread.start();
 1244    // log("MainThread is now waiting a little bit");
 1245    // Thread.sleep(2000); // wait long enough for the other thread to block a bit. Simulate a DB read
 1246    // log("MainThread is now putting something in the cache");
 1247    // cache.put("/SecurityInfo", Integer.toString(23), "HelloWorld");
 1248    // Thread.sleep(2000); // wait long enough for the other thread to block a bit. Simulate a DB read
 1249    // tx.commit();
 1250    // log("MainThread: committed");
 1251    // thread.join(30000);
 1252    //
 1253    // log(cache.get("/SecurityInfo", Integer.toString(23)).toString());
 1254    // }
 1255   
 1256    // public void testConcurrentReadsWithSerializableIsolationLevel() throws CacheException, InterruptedException {
 1257    // final long TIMEOUT=5000;
 1258    // cache.setIsolationLevel(IsolationLevel.SERIALIZABLE);
 1259    // cache.put("/testfqn", "testkey", "testvalue"); // add initial value, to be read by threads
 1260    // Reader r1, r2;
 1261    // r1=new Reader("reader1", 3000);
 1262    // r2=new Reader("reader2", 0);
 1263    // r1.start();
 1264    // pause(100); // make sure thread1 starts and acquires the lock before thread2
 1265    // r2.start();
 1266    // r1.join(TIMEOUT);
 1267    // r2.join(TIMEOUT);
 1268    // }
 1269    //
 1270    // class Reader extends Thread {
 1271    // long timeout;
 1272    //
 1273    // public Reader(String name, long timeout) {
 1274    // super(name);
 1275    // this.timeout=timeout;
 1276    // }
 1277    //
 1278    // public void run() {
 1279    // UserTransaction trans=null;
 1280    // try {
 1281    // trans=(UserTransaction)new InitialContext(p).lookup("UserTransaction");
 1282    // trans.begin();
 1283    // Object retval=null;
 1284    // log2("accessing tree");
 1285    // retval=cache.get("testfqn", "testkey");
 1286    // log2("retval: " + retval);
 1287    // if(timeout > 0) {
 1288    // log2("sleeping for " + timeout + " ms");
 1289    // pause(timeout);
 1290    // }
 1291    // }
 1292    // catch(Exception e) {
 1293    // e.printStackTrace();
 1294    // }
 1295    // finally {
 1296    // try {trans.commit();} catch(Throwable t) {}
 1297    // log2("done");
 1298    // }
 1299    // }
 1300    // }
 1301   
 1302    // private void pause(long timeout) {
 1303    // try {
 1304    // Thread.sleep(timeout);
 1305    // }
 1306    // catch(InterruptedException e) {
 1307    // }
 1308    // }
 1309    //
 1310    // private void log(String msg) {
 1311    // System.out.println("-- [" + Thread.currentThread() + "]: " + msg);
 1312    // }
 1313    //
 1314    // private void log2(String msg) {
 1315    // System.out.println("-- [" + System.currentTimeMillis() + " " + Thread.currentThread() + "]: " + msg);
 1316    // }
 1317   
 1318   
 1319  1 public static Test suite() throws Exception
 1320    {
 1321  1 return new TestSuite(TransactionTest.class);
 1322    }
 1323   
 1324  0 public static void main(String[] args) throws Exception
 1325    {
 1326  0 junit.textui.TestRunner.run(suite());
 1327    }
 1328   
 1329   
 1330    }