package org.apache.niolex.lock; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.niolex.commons.bean.One; import org.apache.niolex.commons.concurrent.ThreadUtil; import org.apache.niolex.commons.reflect.FieldUtil; import org.apache.niolex.commons.test.MockUtil; import org.apache.niolex.commons.util.Runner; import org.apache.niolex.notify.AppTest; import org.apache.niolex.zookeeper.core.ZKConnector; import org.apache.niolex.zookeeper.core.ZKException; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class ZKLockTest { private static String BS = "/lock/zkc/tmp-" + MockUtil.randInt(100, 999); private static ZKConnector ZKC; /** * @throws java.lang.Exception */ @BeforeClass public static void setUpBeforeClass() throws Exception { ZKC = new ZKConnector(AppTest.URL, 10000); String bb = "/lock/zkc"; if (ZKC.exists(bb)) ZKC.deleteTree(bb); } /** * @throws java.lang.Exception */ @AfterClass public static void tearDownAfterClass() throws Exception { List<String> c = ZKC.getChildren(BS); assertEquals(0, c.size()); ZKC.close(); } @Test public void testWholeLock1() throws Exception { ZKLock lock = new ZKLock(ZKC, BS); lock.lock(); lock.unlock(); lock.lock(); lock.unlock(); lock.close(); System.out.println("testWholeLock1 done."); } @Test public void testWholeLock2() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); ZKLock lock2 = new ZKLock(ZKC, BS + "/"); assertTrue(lock1.tryLock()); assertFalse(lock2.tryLock()); lock1.unlock(); assertTrue(lock2.tryLock()); assertFalse(lock1.tryLock()); lock2.unlock(); System.out.println("testWholeLock2 done."); // Unlock again. lock2.unlock(); lock1.close(); lock2.close(); } @Test public void testWholeLock3() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); ZKLock lock2 = new ZKLock(ZKC, BS + "/"); ZKLock lock3 = new ZKLock(ZKC, BS); lock1.lock(); One<Thread> threadVal = One.create(null); Future<Object> fu = Runner.run(threadVal, lock2, "lockInterruptibly"); ThreadUtil.sleepAtLeast(50); assertFalse(lock3.tryLock()); assertFalse(fu.isDone()); lock1.unlock(); assertFalse(lock3.tryLock(100, TimeUnit.MICROSECONDS)); fu.get(); assertFalse(lock3.tryLock()); assertTrue(lock2.locked()); lock2.unlock(); assertFalse(lock2.locked()); assertFalse(lock3.locked()); assertTrue(lock3.tryLock(100, TimeUnit.MICROSECONDS)); assertTrue(lock3.locked()); lock3.unlock(); assertFalse(lock3.locked()); System.out.println("testWholeLock3 done."); lock1.close(); lock2.close(); lock3.close(); } @Test public void testAddAuthInfo() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); lock1.addAuthInfo("abc", "lex"); lock1.close(); } @Test(expected=IllegalStateException.class) public void testInitLockEx() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); lock1.lock(); try { lock1.initLock(); } finally { lock1.unlock(); lock1.close(); } } @Test public void testIsLockReadyWhole() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); ZKLock lock2 = new ZKLock(ZKC, BS + "/"); ZKLock lock3 = new ZKLock(ZKC, BS); ZKLock lock4 = new ZKLock(ZKC, BS + "/"); lock1.lock(); One<Thread> th1 = One.create(null); Future<Object> fu1 = Runner.run(th1, lock2, "lockInterruptibly"); ThreadUtil.sleep(50); One<Thread> th2 = One.create(null); Future<Object> fu2 = Runner.run(th2, lock3, "lockInterruptibly"); ThreadUtil.sleep(50); lock1.unlock(); fu1.get(); assertFalse(lock1.locked()); assertTrue(lock2.locked()); assertFalse(lock3.locked()); assertFalse(lock4.tryLock()); try { lock1.isLockReady(); assertTrue(false); } catch (IllegalStateException e) { assertEquals("Lock not initialized or already released.", e.getMessage()); } lock2.unlock(); fu2.get(); assertFalse(lock1.locked()); assertFalse(lock2.locked()); assertTrue(lock3.locked()); assertTrue(lock3.isLockReady()); assertNull(FieldUtil.getValue(lock4, "selfPath")); FieldUtil.setValue(lock4, "selfPath", "/a/b/c"); assertFalse(lock4.isLockReady()); String p = FieldUtil.getValue(lock4, "selfPath"); System.out.println(p); assertNotNull(p); assertNotEquals("/a/b/c", p); lock3.unlock(); assertTrue(lock4.isLockReady()); lock1.close(); lock2.close(); lock3.close(); lock4.close(); } @Test(expected=IllegalStateException.class) public void testIsLockReadyDirectly() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); try { lock1.isLockReady(); } finally { lock1.close(); } } @Test public void testIsLockReadyLocked() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); FieldUtil.setValue(lock1, "selfPath", "/a/b/c"); FieldUtil.setValue(lock1, "lockStatus", 2); assertTrue(lock1.isLockReady()); } @Test(expected=IllegalStateException.class) public void testWatchLockDirectly() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); try { lock1.watchLock(); } finally { lock1.close(); } } @Test(expected=IllegalStateException.class) public void testWatchLockDirectlyWithTime() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); try { lock1.watchLock(10, TimeUnit.MILLISECONDS); } finally { lock1.close(); } } @Test public void testWatchLockNotExist() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); FieldUtil.setValue(lock1, "selfPath", "/a/b/c"); FieldUtil.setValue(lock1, "watchPath", "/a/b/b"); lock1.watchLock(); } @Test public void testWatchLockReady() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); lock1.initLock(); assertTrue(lock1.isLockReady()); FieldUtil.setValue(lock1, "watchPath", "/a/b/b"); try { lock1.watchLock(10, TimeUnit.MILLISECONDS); } finally { lock1.unlock(); lock1.close(); } } @Test public void testWatchLockWithTime() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); lock1.lock(); FieldUtil.setValue(lock1, "watchPath", "/a/b/b"); lock1.watchLock(10, TimeUnit.MILLISECONDS); ZKLock lock2 = new ZKLock(AppTest.URL, 6000, BS); lock2.initLock(); assertFalse(lock2.isLockReady()); try { FieldUtil.setValue(lock2, "watchPath", "/a/b/b"); lock2.watchLock(); } finally { lock1.unlock(); lock2.unlock(); lock1.close(); lock2.close(); } } @Test(expected=ZKException.class) public void testWatchLockEx() throws Exception { ZooKeeper zk = mock(ZooKeeper.class); ZKConnector zkc = mock(ZKConnector.class); when(zkc.zooKeeper()).thenReturn(zk); KeeperException ke = KeeperException.create(KeeperException.Code.APIERROR); when(zk.exists(anyString(), any(Watcher.class))).thenThrow(ke); ZKLock lock1 = new ZKLock(zkc, BS); FieldUtil.setValue(lock1, "watchPath", "/a/b/c"); lock1.watchLock(); } @Test(expected=ZKException.class) public void testWatchLockExWithTime() throws Exception { ZooKeeper zk = mock(ZooKeeper.class); ZKConnector zkc = mock(ZKConnector.class); when(zkc.zooKeeper()).thenReturn(zk); KeeperException ke = KeeperException.create(KeeperException.Code.APIERROR); when(zk.exists(anyString(), any(Watcher.class))).thenThrow(ke); ZKLock lock1 = new ZKLock(zkc, BS); FieldUtil.setValue(lock1, "watchPath", "/a/b/c"); lock1.watchLock(10, TimeUnit.MILLISECONDS); } @Test public void testWatchLockTimeout() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); lock1.lock(); ZKLock lock2 = new ZKLock(ZKC, BS); lock2.initLock(); assertFalse(lock2.isLockReady()); try { assertFalse(lock2.watchLock(100, TimeUnit.MICROSECONDS)); } finally { lock1.releaseLock(); lock1.close(); lock2.close(); } } @Test public void testWatchLockLongTimeUnit() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); FieldUtil.setValue(lock1, "watchPath", "/a/b/c"); assertTrue(lock1.watchLock(100, TimeUnit.MILLISECONDS)); lock1.close(); } @Test(expected = ZKException.class) public void testWatchLockLongTimeUnitZKEX() throws Exception { ZooKeeper zk = mock(ZooKeeper.class); ZKConnector zkc = mock(ZKConnector.class); when(zkc.zooKeeper()).thenReturn(zk); when(zkc.connected()).thenReturn(false, false, true); KeeperException ke = KeeperException.create(KeeperException.Code.APIERROR); when(zk.exists(anyString(), any(Watcher.class))).thenThrow(ke); ZKLock lock1 = new ZKLock(zkc, BS); try { FieldUtil.setValue(lock1, "watchPath", "/a/b/c"); lock1.watchLock(100, TimeUnit.MILLISECONDS); } finally { lock1.close(); } } @Test public void testReleaseLock() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); lock1.lock(); ZKLock lock2 = new ZKLock(ZKC, BS); lock2.initLock(); assertFalse(lock2.isLockReady()); lock1.releaseLock(); lock2.releaseLock(); lock1.releaseLock(); lock2.releaseLock(); lock1.close(); lock2.close(); } @Test public void testExistsWatherProcess() throws Exception { ZKLock lock1 = new ZKLock(ZKC, BS); CountDownLatch latch = new CountDownLatch(1); Watcher w = lock1.new ExistsWather(latch); lock1.lock(); w.process(new WatchedEvent(Watcher.Event.EventType.None, Watcher.Event.KeeperState.Disconnected, "")); w.process(new WatchedEvent(Watcher.Event.EventType.NodeCreated, Watcher.Event.KeeperState.Disconnected, "")); lock1.unlock(); lock1.close(); } @Test public void testExistsWatherProcess2() throws Exception { ZKConnector zkc = mock(ZKConnector.class); when(zkc.connected()).thenReturn(false, false, true); ZKLock lock1 = new ZKLock(zkc, BS); FieldUtil.setValue(lock1, "watchPath", "/a/b/c"); CountDownLatch latch = new CountDownLatch(1); Watcher w = lock1.new ExistsWather(latch); w.process(new WatchedEvent(Watcher.Event.EventType.None, Watcher.Event.KeeperState.Disconnected, "")); lock1.close(); } @Test(expected=NullPointerException.class) public void testExistsWatherProcess3() throws Exception { ZKConnector zkc = mock(ZKConnector.class); when(zkc.connected()).thenReturn(false, false, true); doThrow(new NullPointerException()).when(zkc).waitForConnectedTillDeath(); ZKLock lock1 = new ZKLock(zkc, BS); CountDownLatch latch = new CountDownLatch(1); Watcher w = lock1.new ExistsWather(latch); w.process(new WatchedEvent(Watcher.Event.EventType.None, Watcher.Event.KeeperState.Disconnected, "")); lock1.close(); } }