diff --git a/src/main/java/io/github/slimefun/e2etester/E2ETester.java b/src/main/java/io/github/slimefun/e2etester/E2ETester.java index f7b067e..ea32f43 100644 --- a/src/main/java/io/github/slimefun/e2etester/E2ETester.java +++ b/src/main/java/io/github/slimefun/e2etester/E2ETester.java @@ -7,8 +7,12 @@ public class E2ETester extends JavaPlugin { + private static E2ETester instance; + @Override public void onEnable() { + instance = this; + final TestFramework framework = TestFramework.newTestRun(); // Wait a second for any startup stuff to be ran @@ -16,4 +20,13 @@ public void onEnable() { framework.runTests("io.github.slimefun.e2etester.tests"); }, 20); } + + @Override + public void onDisable() { + instance = null; + } + + public static E2ETester getInstance() { + return instance; + } } diff --git a/src/main/java/io/github/slimefun/e2etester/framework/TestFramework.java b/src/main/java/io/github/slimefun/e2etester/framework/TestFramework.java index a73e2b1..13529d6 100644 --- a/src/main/java/io/github/slimefun/e2etester/framework/TestFramework.java +++ b/src/main/java/io/github/slimefun/e2etester/framework/TestFramework.java @@ -1,5 +1,7 @@ package io.github.slimefun.e2etester.framework; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; @@ -7,11 +9,14 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.stream.Collectors; import javax.annotation.Nonnull; +import io.github.slimefun.e2etester.E2ETester; import org.bukkit.Bukkit; import org.reflections.Reflections; import org.reflections.scanners.Scanners; @@ -24,6 +29,7 @@ public class TestFramework { private final Map>> eventListeners = new HashMap<>(); + private final ExecutorService service = Executors.newSingleThreadExecutor(); private int testsRan; private int testsPassed; @@ -41,63 +47,76 @@ public void runTests(@Nonnull String packageName) { // TODO: Remove new Startup(); - // Reflection go through all classes - Reflections reflections = new Reflections(ConfigurationBuilder - .build() - .addScanners(Scanners.values()) - .forPackage(packageName, getClass().getClassLoader()) - ); - - logMessage("Running tests..."); - logMessage(""); - - final Set testMethods = reflections.get(Scanners.MethodsAnnotated.with(E2ETest.class).as(Method.class)); - final Map, List> tests = orderTests(testMethods); - for (Map.Entry, List> entry : tests.entrySet()) { - logMessage("%s:", entry.getKey().getName()); - - for (Method method : entry.getValue()) { - String description = method.getAnnotation(E2ETest.class).description(); - - // Invoke - try { - testsRan++; - - method.setAccessible(true); - Object instance = method.getDeclaringClass().getDeclaredConstructor().newInstance(); - method.invoke(instance); - - testsPassed++; - logMessage(" ✔ %s", description); - } catch(TestFailException e) { - testsFailed++; - logMessage(" x %s", description); - e.printStackTrace(); - } catch(Exception e) { - testsFailed++; - logMessage(" x %s", description); - e.printStackTrace(); + service.submit(() -> { + // Reflection go through all classes + Reflections reflections = new Reflections(ConfigurationBuilder + .build() + .addScanners(Scanners.values()) + .forPackage(packageName, getClass().getClassLoader()) + ); + + logMessage("Running tests..."); + logMessage(""); + + final Set testMethods = reflections.get(Scanners.MethodsAnnotated.with(E2ETest.class).as(Method.class)); + final Map, List> tests = orderTests(testMethods); + for (Map.Entry, List> entry : tests.entrySet()) { + logMessage("%s:", entry.getKey().getName()); + + for (Method method : entry.getValue()) { + E2ETest annotation = method.getAnnotation(E2ETest.class); + String description = annotation.description(); + boolean threadSafe = annotation.threadSafe(); + // Invoke + try { + testsRan++; + + method.setAccessible(true); + Object instance = method.getDeclaringClass().getDeclaredConstructor().newInstance(); + if (threadSafe) { + method.invoke(instance); + } else { + Bukkit.getScheduler().runTask(E2ETester.getInstance(), () -> { + try { + method.invoke(instance); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + }); + } + + testsPassed++; + logMessage(" ✔ %s", description); + } catch(TestFailException e) { + testsFailed++; + logMessage(" x %s", description); + e.printStackTrace(); + } catch(Exception e) { + testsFailed++; + logMessage(" x %s", description); + e.printStackTrace(); + } } } - } - - logMessage(""); - logMessage("Test results:"); - logMessage(" Tests ran: %d", this.testsRan); - logMessage(" Tests passed: %d", this.testsPassed); - logMessage(" Tests failed: %d", this.testsFailed); - logMessage(" Tests skipped: %d", this.testsSkipped); - if (this.testsFailed > 0) { - logMessage("Test failure, exiting with code 1"); - System.exit(1); - } else { - Bukkit.shutdown(); - } + logMessage(""); + logMessage("Test results:"); + logMessage(" Tests ran: %d", this.testsRan); + logMessage(" Tests passed: %d", this.testsPassed); + logMessage(" Tests failed: %d", this.testsFailed); + logMessage(" Tests skipped: %d", this.testsSkipped); + + if (this.testsFailed > 0) { + logMessage("Test failure, exiting with code 1"); + System.exit(1); + } else { + Bukkit.getScheduler().runTask(E2ETester.getInstance(), Bukkit::shutdown); + } + }); } public void on(@Nonnull String event, Consumer consumer) { - eventListeners.putIfAbsent(event, new ArrayList>()); + eventListeners.putIfAbsent(event, new ArrayList<>()); ArrayList> value = eventListeners.get(event); if (value != null) { @@ -146,7 +165,7 @@ private Map, List> orderTests(Set methods) { return tests.entrySet().stream() .sorted((entry1, entry2) -> entry1.getKey().getName().compareTo(entry2.getKey().getName())) .collect(Collectors.toMap( - entry -> entry.getKey(), + Map.Entry::getKey, value -> value.getValue().stream() .sorted((method1, method2) -> method1.getName().compareTo(method2.getName())) .toList() diff --git a/src/main/java/io/github/slimefun/e2etester/framework/annotations/E2ETest.java b/src/main/java/io/github/slimefun/e2etester/framework/annotations/E2ETest.java index a903af8..e0ee65e 100644 --- a/src/main/java/io/github/slimefun/e2etester/framework/annotations/E2ETest.java +++ b/src/main/java/io/github/slimefun/e2etester/framework/annotations/E2ETest.java @@ -10,4 +10,5 @@ public @interface E2ETest { String description(); + boolean threadSafe() default false; }