Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 319   Methods: 11
NCLOC: 239   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
PutForExternalReadTestBase.java 73.3% 94.9% 100% 91.2%
coverage coverage
 1    package org.jboss.cache.api.pfer;
 2   
 3    import org.jboss.cache.Cache;
 4    import org.jboss.cache.CacheFactory;
 5    import org.jboss.cache.CacheSPI;
 6    import org.jboss.cache.DefaultCacheFactory;
 7    import org.jboss.cache.Fqn;
 8    import org.jboss.cache.NodeSPI;
 9    import org.jboss.cache.RPCManager;
 10    import org.jboss.cache.RPCManagerImpl;
 11    import org.jboss.cache.config.Configuration;
 12    import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
 13    import org.jboss.cache.lock.NodeLock;
 14    import org.jboss.cache.misc.TestingUtil;
 15    import org.jboss.cache.optimistic.TransactionWorkspace;
 16    import org.jboss.cache.transaction.GlobalTransaction;
 17    import org.jboss.cache.transaction.OptimisticTransactionEntry;
 18    import org.jgroups.Address;
 19    import org.jmock.Mock;
 20    import org.jmock.MockObjectTestCase;
 21    import org.jmock.core.Constraint;
 22   
 23    import javax.transaction.SystemException;
 24    import javax.transaction.Transaction;
 25    import javax.transaction.TransactionManager;
 26    import java.lang.reflect.Method;
 27    import java.util.List;
 28   
 29    public abstract class PutForExternalReadTestBase extends MockObjectTestCase
 30    {
 31    protected Cache<String, String> cache1, cache2;
 32   
 33    protected TransactionManager tm1, tm2;
 34   
 35    protected Fqn<String> fqn = Fqn.fromString("/one/two");
 36    protected Fqn<String> parentFqn = fqn.getParent();
 37   
 38    protected String key = "k", value = "v", value2 = "v2";
 39   
 40    protected boolean useTx, optimistic;
 41    protected Configuration.CacheMode cacheMode;
 42   
 43  20 protected void setUp()
 44    {
 45  20 CacheFactory<String, String> cf = DefaultCacheFactory.getInstance();
 46   
 47  20 cache1 = cf.createCache(UnitTestCacheConfigurationFactory.createConfiguration(cacheMode), false);
 48  20 cache1.getConfiguration().setTransactionManagerLookupClass("org.jboss.cache.transaction.DummyTransactionManagerLookup");
 49  20 cache1.getConfiguration().setNodeLockingScheme(optimistic ? Configuration.NodeLockingScheme.OPTIMISTIC : Configuration.NodeLockingScheme.PESSIMISTIC);
 50   
 51  20 cache1.start();
 52  20 tm1 = cache1.getConfiguration().getRuntimeConfig().getTransactionManager();
 53   
 54  20 cache2 = cf.createCache(UnitTestCacheConfigurationFactory.createConfiguration(cacheMode), false);
 55  20 cache2.getConfiguration().setTransactionManagerLookupClass("org.jboss.cache.transaction.DummyTransactionManagerLookup");
 56  20 cache2.getConfiguration().setNodeLockingScheme(optimistic ? Configuration.NodeLockingScheme.OPTIMISTIC : Configuration.NodeLockingScheme.PESSIMISTIC);
 57   
 58  20 cache2.start();
 59  20 tm2 = cache2.getConfiguration().getRuntimeConfig().getTransactionManager();
 60   
 61  20 TestingUtil.blockUntilViewsReceived(10000, cache1, cache2);
 62    }
 63   
 64  20 protected void tearDown()
 65    {
 66  20 if (cache1 != null)
 67    {
 68  20 if (tm1 != null)
 69    {
 70  20 try
 71    {
 72  20 tm1.rollback();
 73    }
 74    catch (Exception e)
 75    {
 76    // do nothing
 77    }
 78    }
 79  20 cache1.stop();
 80  20 tm1 = null;
 81  20 cache1 = null;
 82    }
 83   
 84  20 if (cache2 != null)
 85    {
 86  20 if (tm2 != null)
 87    {
 88  20 try
 89    {
 90  20 tm2.rollback();
 91    }
 92    catch (Exception e)
 93    {
 94    // do nothing
 95    }
 96    }
 97  20 cache2.stop();
 98  20 tm2 = null;
 99  20 cache2 = null;
 100    }
 101    }
 102   
 103    /**
 104    * Locks could only occur on the parent node is write locked since if the child node exists it is a no-op anyway.
 105    * If the parent node is read locked as well, there is no issue.
 106    */
 107  4 public void testNoOpWhenLockedAnd0msTimeout() throws Exception
 108    {
 109    // create the parent node first ...
 110  4 cache1.put(parentFqn, key, value);
 111   
 112  4 tm1.begin();
 113  4 cache1.put(parentFqn, key, value2);
 114  4 NodeSPI parentNode = null;
 115  4 TransactionWorkspace workspace = null;
 116   
 117  4 if (optimistic)
 118  2 workspace = extractTransactionWorkspace(cache1);
 119    else
 120  2 parentNode = (NodeSPI) cache1.getRoot().getChild(parentFqn);
 121   
 122  4 Transaction t = tm1.suspend();
 123   
 124  4 assertLocked(parentFqn, parentNode, workspace, true);
 125   
 126    // parentFqn should be write-locked.
 127  4 long startTime = System.currentTimeMillis();
 128  4 cache1.putForExternalRead(fqn, key, value);
 129   
 130    // crappy way to test that pFER does not block, but it is effective.
 131  4 assertTrue("Should not wait for lock timeout, should attempt to acquite lock with 0ms!", System.currentTimeMillis() - startTime < cache1.getConfiguration().getLockAcquisitionTimeout());
 132    // should not block.
 133   
 134  4 tm1.resume(t);
 135  4 tm1.commit();
 136   
 137  4 asyncWait();
 138   
 139  4 assertEquals("Parent node write should have succeeded", value2, cache1.get(parentFqn, key));
 140  4 assertEquals("Parent node write should have replicated", value2, cache2.get(parentFqn, key));
 141   
 142  4 if (!optimistic)
 143    {
 144    // doesn't apply with optimistic locking since both txs will succeed here.
 145  2 assertNull("PFER should have been a no-op", cache1.get(fqn, key));
 146  2 assertNull("PFER should have been a no-op", cache2.get(fqn, key));
 147    }
 148    }
 149   
 150  4 public void testNoOpWhenNodePresent()
 151    {
 152  4 cache1.putForExternalRead(fqn, key, value);
 153  4 asyncWait();
 154   
 155  4 assertEquals("PFER should have succeeded", value, cache1.get(fqn, key));
 156  4 assertEquals("PFER should have replicated", value, cache2.get(fqn, key));
 157   
 158    // reset
 159  4 cache1.removeNode(fqn);
 160  4 asyncWait();
 161   
 162  4 assertFalse("Should have reset", cache1.getRoot().hasChild(fqn));
 163  4 assertFalse("Should have reset", cache2.getRoot().hasChild(fqn));
 164   
 165  4 cache1.put(fqn, key, value);
 166  4 asyncWait();
 167   
 168    // now this pfer should be a no-op
 169  4 cache1.putForExternalRead(fqn, key, value2);
 170   
 171  4 assertEquals("PFER should have been a no-op", value, cache1.get(fqn, key));
 172  4 assertEquals("PFER should have been a no-op", value, cache2.get(fqn, key));
 173    }
 174   
 175  4 public void testAsyncForce()
 176    {
 177  4 Mock mockRpcManager = mock(RPCManager.class);
 178  4 RPCManager originalRpcManager = cache1.getConfiguration().getRuntimeConfig().getRPCManager();
 179   
 180    // inject a mock RPC manager so that we can test whether calls made are sync or async.
 181  4 cache1.getConfiguration().getRuntimeConfig().setRPCManager((RPCManager) mockRpcManager.proxy());
 182   
 183    // specify what we expect called on the mock Rpc Manager. For params we don't care about, just use ANYTHING.
 184    // setting the mock object to expect the "sync" param to be false.
 185  4 mockRpcManager.expects(once()).method("getReplicationQueue").withNoArguments();
 186  4 mockRpcManager.expects(once()).method("callRemoteMethods").with(new Constraint[]{ANYTHING, ANYTHING, ANYTHING, eq(false), ANYTHING, ANYTHING});
 187    // now try a simple replication. Since the RPCManager is a mock object it will not actually replicate anything.
 188  4 cache1.putForExternalRead(fqn, key, value);
 189   
 190    // cleanup
 191  4 cache1.getConfiguration().getRuntimeConfig().setRPCManager(originalRpcManager);
 192  4 cache1.removeNode(fqn);
 193    }
 194   
 195  4 public void testTxSuspension() throws Exception
 196    {
 197    // create parent node first
 198  4 cache1.put(parentFqn, key, value);
 199   
 200    // start a tx and do some stuff.
 201  4 tm1.begin();
 202  4 cache1.get(parentFqn, key);
 203  4 NodeSPI parentNode = null;
 204  4 TransactionWorkspace workspace = null;
 205  4 if (optimistic)
 206  2 workspace = extractTransactionWorkspace(cache1);
 207    else
 208  2 parentNode = (NodeSPI) cache1.getRoot().getChild(parentFqn);
 209   
 210  4 cache1.putForExternalRead(fqn, key, value); // should have happened in a separate tx and have committed already.
 211  4 Transaction t = tm1.suspend();
 212   
 213  4 asyncWait();
 214   
 215  4 assertLocked(parentFqn, parentNode, workspace, false);
 216   
 217  4 assertEquals("PFER should have completed", value, cache1.get(fqn, key));
 218  4 assertEquals("PFER should have completed", value, cache2.get(fqn, key));
 219   
 220  4 tm1.resume(t);
 221  4 tm1.commit();
 222   
 223  4 asyncWait();
 224   
 225  4 assertEquals("parent fqn tx should have completed", value, cache1.get(parentFqn, key));
 226  4 assertEquals("parent fqn tx should have completed", value, cache2.get(parentFqn, key));
 227    }
 228   
 229  4 public void testExceptionSuppression()
 230    {
 231  4 RPCManager barfingRpcManager = new RPCManagerImpl()
 232    {
 233  14 public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout)
 234    {
 235  14 throw new RuntimeException("Barf");
 236    }
 237    };
 238   
 239  4 barfingRpcManager.setCache((CacheSPI) cache1);
 240  4 cache1.getConfiguration().getRuntimeConfig().setRPCManager(barfingRpcManager);
 241   
 242  4 try
 243    {
 244  4 cache1.put(fqn, key, value);
 245  0 if (!optimistic) fail("Should have barfed");
 246    }
 247    catch (RuntimeException re)
 248    {
 249    }
 250   
 251  4 if (optimistic)
 252    {
 253    // proves that the put did, in fact, barf.
 254  2 assertNull(cache1.get(fqn, key));
 255    }
 256    else
 257    {
 258    // clean up any indeterminate state left over
 259  2 try
 260    {
 261  2 cache1.removeNode(fqn);
 262  0 fail("Should have barfed");
 263    }
 264    catch (RuntimeException re)
 265    {
 266    }
 267    }
 268   
 269  4 assertNull("Should have cleaned up", cache1.get(fqn, key));
 270   
 271    // should not barf
 272  4 cache1.putForExternalRead(fqn, key, value);
 273    }
 274   
 275  8 protected void assertLocked(Fqn fqn, NodeSPI n, TransactionWorkspace workspace, boolean write_locked) throws Exception
 276    {
 277    // this needs to cater for "optimistically locked" nodes as well.
 278  8 if (workspace != null)
 279    {
 280    // scan workspaces for this node
 281  4 assertNotNull("node " + fqn + " should be in transaction workspace", workspace.getNode(fqn));
 282    }
 283    else
 284    {
 285  4 NodeLock lock = n.getLock();
 286  4 assertTrue("node " + fqn + " is not locked", lock.isLocked());
 287  4 if (write_locked)
 288    {
 289  2 assertTrue("node " + fqn + " is not write-locked" + (lock.isReadLocked() ? " but is read-locked instead!" : "!"), lock.isWriteLocked());
 290    }
 291    else
 292    {
 293  2 assertTrue("node " + fqn + " is not read-locked" + (lock.isWriteLocked() ? " but is write-locked instead!" : "!"), lock.isReadLocked());
 294    }
 295    }
 296    }
 297   
 298  4 protected TransactionWorkspace extractTransactionWorkspace(Cache c)
 299    {
 300  4 CacheSPI cs = (CacheSPI) c;
 301  4 try
 302    {
 303  4 GlobalTransaction gtx = cs.getTransactionTable().get(cs.getTransactionManager().getTransaction());
 304  4 OptimisticTransactionEntry entry = (OptimisticTransactionEntry) cs.getTransactionTable().get(gtx);
 305  4 return entry.getTransactionWorkSpace();
 306    }
 307    catch (SystemException e)
 308    {
 309  0 e.printStackTrace();
 310  0 fail("Unable to extract transaction workspace from cache");
 311    }
 312  0 return null;
 313    }
 314   
 315  24 protected void asyncWait()
 316    {
 317  24 TestingUtil.sleepThread(500);
 318    }
 319    }