From 6ab86583999ed761c81109388620449ad1c3d53a Mon Sep 17 00:00:00 2001 From: Daniil Date: Sun, 5 Aug 2018 13:40:02 +0700 Subject: [PATCH] LockObserveList implementation, tests for Lock and List --- core/src/main/java/mc/core/Location.java | 25 ++++-- .../mc/core/events/lock/LockObserveList.java | 44 +++++++++ .../test/java/mc/core/events/LockTest.java | 90 +++++++++++++++++++ 3 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 event-loop/src/main/java/mc/core/events/lock/LockObserveList.java create mode 100644 event-loop/src/test/java/mc/core/events/LockTest.java diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 7e560f3..608d764 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -6,17 +6,23 @@ package mc.core; import lombok.AllArgsConstructor; import lombok.Data; +import mc.core.world.Chunk; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; import java.io.Serializable; @AllArgsConstructor @Data -public class Location implements Serializable{ +public class Location implements Serializable { private double x, y, z; + public Location(long compactValue) { + set(compactValue); + } + private static int floor_double(double value) { - int i = (int)value; - return value < (double)i ? i - 1 : i; + int i = (int) value; + return value < (double) i ? i - 1 : i; } public static Location copyOf(Location location) { @@ -27,12 +33,8 @@ public class Location implements Serializable{ ); } - public static Location startPointLocation () { - return new Location(0,10,0); - } - - public Location(long compactValue) { - set(compactValue); + public static Location startPointLocation() { + return new Location(0, 10, 0); } public void set(Location location) { @@ -55,6 +57,11 @@ public class Location implements Serializable{ ); } + public Chunk getChunk() { + // TODO: Implement + throw new NotImplementedException(); + } + public int getBlockX() { return (int) x; } diff --git a/event-loop/src/main/java/mc/core/events/lock/LockObserveList.java b/event-loop/src/main/java/mc/core/events/lock/LockObserveList.java new file mode 100644 index 0000000..800a1b6 --- /dev/null +++ b/event-loop/src/main/java/mc/core/events/lock/LockObserveList.java @@ -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 { + private List 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(); + } + } + } +} diff --git a/event-loop/src/test/java/mc/core/events/LockTest.java b/event-loop/src/test/java/mc/core/events/LockTest.java new file mode 100644 index 0000000..97b22e2 --- /dev/null +++ b/event-loop/src/test/java/mc/core/events/LockTest.java @@ -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()); + + } +}