Archived
0

LockObserveList implementation, tests for Lock and List

This commit is contained in:
Daniil
2018-08-05 13:40:02 +07:00
parent b5a7942b67
commit 6ab8658399
3 changed files with 150 additions and 9 deletions

View File

@@ -0,0 +1,44 @@
package mc.core.events.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class LockObserveList implements Consumer<PoorMansLock> {
private List<PoorMansLock> locks = new ArrayList<>();
private Runnable callback;
public void setCallback(Runnable callback) {
this.callback = callback;
}
public void add(PoorMansLock lock) {
locks.add(lock);
lock.addCallback(this);
}
public void release() {
for (PoorMansLock lock : locks) {
lock.removeCallback(this);
}
locks.clear();
}
public boolean isReady() {
for (PoorMansLock lock : locks) {
if (lock.isLocked())
return false;
}
return true;
}
@Override
public void accept(PoorMansLock lock) {
if (!lock.isLocked()) {
if (isReady()) {
if (callback != null)
callback.run();
}
}
}
}

View File

@@ -0,0 +1,90 @@
package mc.core.events;
import mc.core.events.lock.LockObserveList;
import mc.core.events.lock.PoorMansLock;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
public class LockTest {
@Test
public void basicTest() throws InterruptedException {
AtomicBoolean engageCallbackCalled = new AtomicBoolean(false);
AtomicBoolean disengageCallbackCalled = new AtomicBoolean(false);
PoorMansLock lock = new PoorMansLock();
lock.addCallback(lock1 -> {
if (lock1.isLocked())
engageCallbackCalled.set(true);
else
disengageCallbackCalled.set(true);
});
lock.lock();
Assert.assertTrue("Lock is not locked", lock.isLocked());
Assert.assertTrue("Engage callback was not called", engageCallbackCalled.get());
engageCallbackCalled.set(false);
try {
lock.lock();
Assert.assertFalse("Engage callback was called from attempt to block from the same thread", engageCallbackCalled.get());
} catch (Exception ex) {
Assert.fail("Exception fired while attempting to lock from the same thread");
return;
}
Assert.assertFalse("Disengage callback was called while not actually disengaging [x1]", disengageCallbackCalled.get());
AtomicBoolean lockExceptionFired = new AtomicBoolean(false);
AtomicBoolean unlockExceptionFired = new AtomicBoolean(false);
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
try {
lock.lock();
} catch (Exception ex) {
lockExceptionFired.set(true);
}
try {
lock.unlock();
} catch (Exception ex) {
unlockExceptionFired.set(true);
}
latch.countDown();
}).start();
latch.await();
Assert.assertTrue("Exception was not fired on concurrent lock attempt", lockExceptionFired.get());
Assert.assertTrue("Exception was not fired on non-owner unlock attempt", unlockExceptionFired.get());
Assert.assertFalse("Disengage callback was called while not actually disengaging [x2]", disengageCallbackCalled.get());
lock.unlock();
Assert.assertTrue("Disengage callback was on called on lock disengage", disengageCallbackCalled.get());
}
@Test
public void observeListTest() {
PoorMansLock lock1 = new PoorMansLock();
PoorMansLock lock2 = new PoorMansLock();
LockObserveList list = new LockObserveList();
list.add(lock1);
list.add(lock2);
Assert.assertTrue("LockObserveList was no able to correctly identify lock states for unlocked locks", list.isReady());
lock1.lock();
Assert.assertFalse("LockObserveList was no able to correctly identify lock states for list with one locked lock", list.isReady());
AtomicBoolean listReadyCallbackCalled = new AtomicBoolean(false);
list.setCallback(() -> listReadyCallbackCalled.set(true));
lock2.lock();
Assert.assertFalse("Callback was called when another lock got engaged", listReadyCallbackCalled.get());
lock1.unlock();
Assert.assertFalse("Callback was called while one lock is still locked", listReadyCallbackCalled.get());
lock2.unlock();
Assert.assertTrue("Callback was not called when both locks are actually free", listReadyCallbackCalled.get());
}
}