From 9e73a8887c5f142abbc7a324df17d167b2427478 Mon Sep 17 00:00:00 2001 From: Wesley Wolfe Date: Wed, 13 Jun 2012 21:28:13 -0500 Subject: Support asynchronous events; Addresses BUKKIT-1212 --- src/test/java/org/bukkit/TestServer.java | 48 +++++++++ src/test/java/org/bukkit/event/TestEvent.java | 19 ++++ .../java/org/bukkit/plugin/PluginManagerTest.java | 118 +++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/test/java/org/bukkit/TestServer.java create mode 100644 src/test/java/org/bukkit/event/TestEvent.java create mode 100644 src/test/java/org/bukkit/plugin/PluginManagerTest.java (limited to 'src/test') diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java new file mode 100644 index 00000000..63e8aeff --- /dev/null +++ b/src/test/java/org/bukkit/TestServer.java @@ -0,0 +1,48 @@ +package org.bukkit; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; + + +public class TestServer implements InvocationHandler { + private static interface MethodHandler { + Object handle(TestServer server, Object[] args); + } + private static final Constructor constructor; + private static final HashMap methods = new HashMap(); + static { + try { + methods.put(Server.class.getMethod("isPrimaryThread"), + new MethodHandler() { + public Object handle(TestServer server, Object[] args) { + return Thread.currentThread().equals(server.creatingThread); + } + }); + constructor = Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class); + } catch (Throwable t) { + throw new Error(t); + } + } + + private Thread creatingThread = Thread.currentThread(); + private TestServer() {}; + + public static Server getInstance() { + try { + return constructor.newInstance(new TestServer()); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + public Object invoke(Object proxy, Method method, Object[] args) { + MethodHandler handler = methods.get(method); + if (handler != null) { + return handler.handle(this, args); + } + throw new UnsupportedOperationException(String.valueOf(method)); + } +} diff --git a/src/test/java/org/bukkit/event/TestEvent.java b/src/test/java/org/bukkit/event/TestEvent.java new file mode 100644 index 00000000..c06dfe94 --- /dev/null +++ b/src/test/java/org/bukkit/event/TestEvent.java @@ -0,0 +1,19 @@ +package org.bukkit.event; + + +public class TestEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + public TestEvent(boolean async) { + super(async); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/test/java/org/bukkit/plugin/PluginManagerTest.java b/src/test/java/org/bukkit/plugin/PluginManagerTest.java new file mode 100644 index 00000000..b5cb7408 --- /dev/null +++ b/src/test/java/org/bukkit/plugin/PluginManagerTest.java @@ -0,0 +1,118 @@ +package org.bukkit.plugin; + +import static junit.framework.Assert.*; + +import org.bukkit.Server; +import org.bukkit.TestServer; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.event.Event; +import org.bukkit.event.TestEvent; +import org.junit.Test; + +public class PluginManagerTest { + private class MutableObject { + volatile Object value = null; + } + + final Server server = TestServer.getInstance(); + final SimpleCommandMap commandMap = new SimpleCommandMap(server); + final PluginManager pm = new SimplePluginManager(server, commandMap); + final MutableObject store = new MutableObject(); + + @Test + public void testAsyncSameThread() { + final Event event = new TestEvent(true); + try { + pm.callEvent(event); + } catch (IllegalStateException ex) { + assertEquals(event.getEventName() + " cannot be triggered asynchronously from primary server thread.", ex.getMessage()); + return; + } + throw new IllegalStateException("No exception thrown"); + } + + @Test + public void testSyncSameThread() { + final Event event = new TestEvent(false); + pm.callEvent(event); + } + + @Test + public void testAsyncLocked() throws InterruptedException { + final Event event = new TestEvent(true); + Thread secondThread = new Thread( + new Runnable() { + public void run() { + try { + synchronized (pm) { + pm.callEvent(event); + } + } catch (Throwable ex) { + store.value = ex; + } + }}); + secondThread.start(); + secondThread.join(); + assertTrue(store.value instanceof IllegalStateException); + assertEquals(event.getEventName() + " cannot be triggered asynchronously from inside synchronized code.", ((Throwable) store.value).getMessage()); + } + + @Test + public void testAsyncUnlocked() throws InterruptedException { + final Event event = new TestEvent(true); + Thread secondThread = new Thread( + new Runnable() { + public void run() { + try { + pm.callEvent(event); + } catch (Throwable ex) { + store.value = ex; + } + }}); + secondThread.start(); + secondThread.join(); + if (store.value != null) { + throw new RuntimeException((Throwable) store.value); + } + } + + @Test + public void testSyncUnlocked() throws InterruptedException { + final Event event = new TestEvent(false); + Thread secondThread = new Thread( + new Runnable() { + public void run() { + try { + pm.callEvent(event); + } catch (Throwable ex) { + store.value = ex; + } + }}); + secondThread.start(); + secondThread.join(); + if (store.value != null) { + throw new RuntimeException((Throwable) store.value); + } + } + + @Test + public void testSyncLocked() throws InterruptedException { + final Event event = new TestEvent(false); + Thread secondThread = new Thread( + new Runnable() { + public void run() { + try { + synchronized (pm) { + pm.callEvent(event); + } + } catch (Throwable ex) { + store.value = ex; + } + }}); + secondThread.start(); + secondThread.join(); + if (store.value != null) { + throw new RuntimeException((Throwable) store.value); + } + } +} -- cgit v1.2.3