Author: manik.surtani(a)jboss.com
Date: 2008-06-27 12:55:51 -0400 (Fri, 27 Jun 2008)
New Revision: 6103
Modified:
core/trunk/src/test/java/org/jboss/cache/api/mvcc/CacheAPIMVCCTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockParentForChildInsertRemoveTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeAPIMVCCTest.java
core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerNoTxTest.java
core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerRecordingTest.java
core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerTest.java
core/trunk/src/test/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockTest.java
Log:
MVCC tests
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/CacheAPIMVCCTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/CacheAPIMVCCTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/CacheAPIMVCCTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -8,7 +8,7 @@
/**
* MVCC version of {@link org.jboss.cache.api.CacheAPITest}
*/
-@Test(groups = "functional")
+@Test(groups = {"functional", "mvcc"})
public class CacheAPIMVCCTest extends CacheAPITest
{
@Override
Modified:
core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockParentForChildInsertRemoveTest.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockParentForChildInsertRemoveTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++
core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockParentForChildInsertRemoveTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -2,7 +2,7 @@
import org.testng.annotations.Test;
-@Test(groups = "functional")
+@Test(groups = {"functional", "mvcc"})
public class LockParentForChildInsertRemoveTest extends LockTest
{
public LockParentForChildInsertRemoveTest()
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockTest.java 2008-06-27 16:55:10
UTC (rev 6102)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockTest.java 2008-06-27 16:55:51
UTC (rev 6103)
@@ -7,6 +7,7 @@
import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
import org.jboss.cache.invocation.InvocationContextContainer;
+import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.lock.LockManager;
import org.jboss.cache.lock.MVCCLockManager.LockContainer;
import org.jboss.cache.transaction.DummyTransactionManagerLookup;
@@ -15,6 +16,7 @@
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.Collections;
@@ -22,7 +24,7 @@
* @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
* @since 3.0
*/
-@Test(groups = "functional")
+@Test(groups = {"functional", "mvcc"})
public class LockTest
{
Cache<String, String> cache;
@@ -30,10 +32,13 @@
Fqn A = Fqn.fromString("/a");
Fqn AB = Fqn.fromString("/a/b");
Fqn ABC = Fqn.fromString("/a/b/c");
+ Fqn ABCD = Fqn.fromString("/a/b/c/d");
LockManager lockManager;
InvocationContextContainer icc;
boolean lockParentForInsertRemove = false;
+ boolean repeatableRead = true;
+
@BeforeMethod
public void setUp()
{
@@ -41,6 +46,7 @@
cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
cache.getConfiguration().setLockParentForChildInsertRemove(lockParentForInsertRemove);
+ cache.getConfiguration().setIsolationLevel(repeatableRead ?
IsolationLevel.REPEATABLE_READ : IsolationLevel.READ_COMMITTED);
cache.start();
lockManager =
TestingUtil.extractComponentRegistry(cache).getComponent(LockManager.class);
icc =
TestingUtil.extractComponentRegistry(cache).getComponent(InvocationContextContainer.class);
@@ -151,8 +157,264 @@
assertNoLocks();
}
- // TODO: Test other major API methods - remove, etc.
- // TODO: Test that writes don't block reads.
+ public void testLocksOnRemoveNode() throws Exception
+ {
+ // init some data on a node
+ cache.put(AB, Collections.singletonMap("k", "v"));
+
+ assert "v".equals(cache.get(AB, "k"));
+
+ tm.begin();
+ cache.removeNode(AB);
+ assertLocked(AB);
+ if (lockParentForInsertRemove)
+ assertLocked(A);
+ else
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.getNode(AB) == null : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnEvictNode() throws Exception
+ {
+ // init some data on a node
+ cache.put(AB, Collections.singletonMap("k", "v"));
+
+ assert "v".equals(cache.get(AB, "k"));
+
+ tm.begin();
+ cache.evict(AB);
+ assertLocked(AB);
+ if (lockParentForInsertRemove)
+ assertLocked(A);
+ else
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.getNode(AB) == null : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnEvictRecursiveNode() throws Exception
+ {
+ // init some data on a node
+ cache.put(AB, Collections.singletonMap("k", "v"));
+ cache.put(ABC, Collections.singletonMap("k", "v"));
+ cache.put(ABCD, Collections.singletonMap("k", "v"));
+
+ assert "v".equals(cache.get(AB, "k"));
+ assert "v".equals(cache.get(ABC, "k"));
+ assert "v".equals(cache.get(ABCD, "k"));
+
+ tm.begin();
+ cache.evict(AB, true);
+ assertLocked(AB);
+ assertLocked(ABC);
+ assertLocked(ABCD);
+ if (lockParentForInsertRemove)
+ assertLocked(A);
+ else
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.getNode(AB) == null : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnRemoveNonexistentNode() throws Exception
+ {
+ assert cache.getNode(AB) == null : "Should not exist";
+
+ tm.begin();
+ cache.removeNode(AB);
+ assertLocked(AB);
+ if (lockParentForInsertRemove)
+ assertLocked(A);
+ else
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.getNode(AB) == null : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnEvictNonexistentNode() throws Exception
+ {
+ assert cache.getNode(AB) == null : "Should not exist";
+
+ tm.begin();
+ cache.evict(AB);
+ assertLocked(AB);
+ if (lockParentForInsertRemove)
+ assertLocked(A);
+ else
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.getNode(AB) == null : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnRemoveData() throws Exception
+ {
+ // init some data on a node
+ cache.put(AB, "k", "v");
+ cache.put(AB, "k2", "v2");
+
+ assert "v".equals(cache.get(AB, "k"));
+ assert "v2".equals(cache.get(AB, "k2"));
+
+ // remove
+ tm.begin();
+ Object x = cache.remove(AB, "k");
+ assert x.equals("v");
+ assertLocked(AB);
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.get(AB, "k") == null : "Should not exist";
+ assert "v2".equals(cache.get(AB, "k2"));
+ assertNoLocks();
+
+ // clearData
+ tm.begin();
+ cache.clearData(AB);
+ assertLocked(AB);
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+
+ assert cache.get(AB, "k") == null : "Should not exist";
+ assert cache.get(AB, "k2") == null : "Should not exist";
+ assertNoLocks();
+
+ // nonexistent key
+ assert cache.get(AB, "k3") == null : "Should not exist";
+ tm.begin();
+ cache.remove(AB, "k3");
+ assertLocked(AB);
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assertNoLocks();
+ }
+
+ public void testLocksOnRemoveDataNonExistentNode() throws Exception
+ {
+ assert cache.getNode(AB) == null : "Should not exist";
+
+ tm.begin();
+ cache.remove(AB, "k");
+ assertNotLocked(AB);
+ assertNotLocked(A);
+ assertNotLocked(Fqn.ROOT);
+ tm.commit();
+ assert cache.getNode(AB) == null : "Should not exist";
+ }
+
+ public void testReadMethods() throws Exception
+ {
+ cache.put(AB, "k", "v");
+
+ tm.begin();
+ assert "v".equals(cache.get(AB, "k"));
+ assertNoLocks();
+ tm.commit();
+ assertNoLocks();
+
+ tm.begin();
+ assert cache.getData(AB).containsKey("k");
+ assertNoLocks();
+ tm.commit();
+ assertNoLocks();
+
+ tm.begin();
+ assert cache.getKeys(AB).contains("k");
+ assertNoLocks();
+ tm.commit();
+ assertNoLocks();
+
+ tm.begin();
+ assert cache.getNode(AB) != null;
+ assertNoLocks();
+ tm.commit();
+ assertNoLocks();
+
+ tm.begin();
+ assert !(cache.getNode(A).getChildrenNames().isEmpty());
+ assertNoLocks();
+ tm.commit();
+ assertNoLocks();
+ }
+
+ public void testWriteDoesntBlockRead() throws Exception
+ {
+ cache.put(AB, "k", "v");
+
+ // start a write.
+ tm.begin();
+ cache.put(AB, "k2", "v2");
+ assertLocked(AB);
+ Transaction write = tm.suspend();
+
+ // now start a read and confirm that the write doesn't block it.
+ tm.begin();
+ assert "v".equals(cache.get(AB, "k"));
+ assert null == cache.get(AB, "k2") : "Should not see uncommitted
changes";
+ Transaction read = tm.suspend();
+
+ // commit the write
+ tm.resume(write);
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.resume(read);
+ if (repeatableRead)
+ assert null == cache.get(AB, "k2") : "Should have repeatable
read";
+ else
+ assert "v2".equals(cache.get(AB, "k2")) : "Read
committed should see committed changes";
+ tm.commit();
+ assertNoLocks();
+ }
+
+ public void testWriteDoesntBlockReadNonexistent() throws Exception
+ {
+ // start a write.
+ tm.begin();
+ cache.put(AB, "k", "v");
+ assertLocked(AB);
+ Transaction write = tm.suspend();
+
+ // now start a read and confirm that the write doesn't block it.
+ tm.begin();
+ assert null == cache.get(AB, "k") : "Should not see uncommitted
changes";
+ assert null == cache.getNode(AB);
+ Transaction read = tm.suspend();
+
+ // commit the write
+ tm.resume(write);
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.resume(read);
+ if (repeatableRead)
+ {
+ assert null == cache.get(AB, "k") : "Should have repeatable
read";
+ assert null == cache.getNode(AB);
+ }
+ else
+ {
+ assert "v".equals(cache.get(AB, "k")) : "Read committed
should see committed changes";
+ assert null != cache.getNode(AB);
+ }
+ tm.commit();
+ assertNoLocks();
+ }
+
// TODO: Test write conflicts - with and without allowing write skew. Multiple cases
involving concurrent removes, concurrent put + remove, etc.
// TODO: Test Replication with MVCC
// TODO: Test state transfer with MVCC
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeAPIMVCCTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeAPIMVCCTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeAPIMVCCTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -11,7 +11,7 @@
/**
* An MVCC version of {@link org.jboss.cache.api.NodeAPITest}
*/
-@Test(groups = "functional")
+@Test(groups = {"functional", "mvcc"})
public class NodeAPIMVCCTest extends NodeAPITest
{
protected NodeLockingScheme getNodeLockingScheme()
Modified: core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerNoTxTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerNoTxTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++ core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerNoTxTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -4,7 +4,7 @@
import javax.transaction.TransactionManager;
-@Test(groups = "unit")
+@Test(groups = {"unit", "mvcc"})
public class MVCCLockManagerNoTxTest extends MVCCLockManagerTest
{
@Override
Modified: core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerRecordingTest.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerRecordingTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++
core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerRecordingTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -17,7 +17,7 @@
* @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
* @since 3.0
*/
-@Test(groups = "unit")
+@Test(groups = {"unit", "mvcc"})
public class MVCCLockManagerRecordingTest extends AbstractLockManagerRecordingTest
{
@BeforeMethod
Modified: core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++ core/trunk/src/test/java/org/jboss/cache/lock/MVCCLockManagerTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -15,7 +15,7 @@
import javax.transaction.TransactionManager;
-@Test(groups = "unit")
+@Test(groups = {"unit", "mvcc"})
public class MVCCLockManagerTest
{
MVCCLockManager lm;
Modified:
core/trunk/src/test/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockTest.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockTest.java 2008-06-27
16:55:10 UTC (rev 6102)
+++
core/trunk/src/test/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockTest.java 2008-06-27
16:55:51 UTC (rev 6103)
@@ -13,7 +13,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-@Test(groups = "unit")
+@Test(groups = {"unit", "mvcc"})
public class OwnableReentrantLockTest
{
private InvocationContextContainer getInvocationContextContainer()