diff --git a/build.gradle.kts b/build.gradle.kts
index faed50c617..22dca7fb3f 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -38,6 +38,8 @@ subprojects {
             exceptionFormat = TestExceptionFormat.FULL
             events(TestLogEvent.STANDARD_OUT)
         }
+        minHeapSize = "2g"
+        maxHeapSize = "2g"
     }
 
     repositories {
diff --git a/patches/api/Add-Material-Tags.patch b/patches/api/Add-Material-Tags.patch
index 5045aa6216..0d8e06e287 100644
--- a/patches/api/Add-Material-Tags.patch
+++ b/patches/api/Add-Material-Tags.patch
@@ -1146,8 +1146,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import io.papermc.paper.tag.BaseTag;
 +import io.papermc.paper.tag.EntityTags;
++import io.papermc.paper.testing.TestServer;
 +import org.bukkit.Bukkit;
-+import org.bukkit.TestServer;
 +import org.junit.Before;
 +import org.junit.Test;
 +
@@ -1163,7 +1163,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    @Before
 +    public void before() {
-+        TestServer.getInstance();
++        TestServer.setup();
 +    }
 +
 +    @Test
@@ -1211,20 +1211,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@
 +package io.papermc.paper;
 +
-+import com.destroystokyo.paper.MaterialTags;
 +import io.papermc.paper.tag.EntityTags;
-+import org.bukkit.Bukkit;
-+import org.bukkit.TestServer;
-+import org.junit.Test;
-+
++import io.papermc.paper.testing.TestServer;
 +import java.util.logging.Level;
++import org.bukkit.Bukkit;
++import org.junit.Test;
 +
 +public class EntityTagsTest {
 +
 +    @Test
 +    public void testInitialize() {
 +        try {
-+            TestServer.getInstance();
++            TestServer.setup();
 +            EntityTags.HORSES.getValues();
 +            assert true;
 +        } catch (Throwable e) {
@@ -1233,24 +1231,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        }
 +    }
 +}
-diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/test/java/org/bukkit/TestServer.java
-+++ b/src/test/java/org/bukkit/TestServer.java
-@@ -0,0 +0,0 @@ public final class TestServer implements InvocationHandler {
-                         }
-                     }
-                 );
-+            // Paper start
-+            methodMap.put(
-+                Server.class.getMethod("getTag", String.class, NamespacedKey.class, Class.class),
-+                new MethodHandler() {
-+                    public Object handle(TestServer server, Object[] args) {
-+                        return new com.destroystokyo.paper.MaterialSetTag();
-+                    }
-+                }
-+            );
-+            // Paper end
-             methodMap.put(
-                     Server.class.getMethod("getPluginManager"),
-                     new MethodHandler() {
diff --git a/patches/api/Annotation-Test-changes.patch b/patches/api/Annotation-Test-changes.patch
deleted file mode 100644
index c063fdab0d..0000000000
--- a/patches/api/Annotation-Test-changes.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Shane Freeder <theboyetronic@gmail.com>
-Date: Sun, 17 Mar 2019 23:04:30 +0000
-Subject: [PATCH] Annotation Test changes
-
-- Allow use of TYPE_USE annotations
-- Ignore package-private methods for nullability annotations
-- Add excludes for classes which don't pass
-
-diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/test/java/org/bukkit/AnnotationTest.java
-+++ b/src/test/java/org/bukkit/AnnotationTest.java
-@@ -0,0 +0,0 @@ public class AnnotationTest {
-         "org/bukkit/util/io/Wrapper",
-         "org/bukkit/plugin/java/PluginClassLoader",
-         // Generic functional interface
--        "org/bukkit/util/Consumer"
-+        "org/bukkit/util/Consumer",
-+        // Paper start
-+        // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull
-+        "co/aikar/timings/TimingHistory$2",
-+        "co/aikar/timings/TimingHistory$2$1",
-+        "co/aikar/timings/TimingHistory$2$1$1",
-+        "co/aikar/timings/TimingHistory$2$1$2",
-+        "co/aikar/timings/TimingHistory$3",
-+        "co/aikar/timings/TimingHistory$4",
-+        "co/aikar/timings/TimingHistoryEntry$1"
-+        // Paper end
-     };
- 
-     @Test
-@@ -0,0 +0,0 @@ public class AnnotationTest {
-                 }
- 
-                 if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) {
-+                    // Paper start - Allow use of TYPE_USE annotations
-+                    boolean warn = true;
-+                    if (isWellAnnotated(method.visibleTypeAnnotations)) {
-+                        warn = false;
-+                    } else if (method.invisibleTypeAnnotations != null) {
-+                        dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) {
-+                            final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef);
-+                            if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) {
-+                                warn = false;
-+                                break dance; // cha cha real smooth
-+                            }
-+                        }
-+                    }
-+                    if (warn)
-+                    // Paper end
-                     warn(errors, clazz, method, "return value");
-                 }
- 
-                 Type[] paramTypes = Type.getArgumentTypes(method.desc);
-                 List<ParameterNode> parameters = method.parameters;
- 
-+                dancing: // Paper
-                 for (int i = 0; i < paramTypes.length; i++) {
-                     if (mustBeAnnotated(paramTypes[i]) ^ isWellAnnotated(method.invisibleParameterAnnotations == null ? null : method.invisibleParameterAnnotations[i])) {
-+                        // Paper start
-+                        if (method.invisibleTypeAnnotations != null) {
-+                            for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) {
-+                                final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef);
-+                                if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) {
-+                                    continue dancing;
-+                                }
-+                            }
-+                        }
-+                        // Paper end - Allow use of TYPE_USE annotations
-                         ParameterNode paramNode = parameters == null ? null : parameters.get(i);
-                         String paramName = paramNode == null ? null : paramNode.name;
- 
-@@ -0,0 +0,0 @@ public class AnnotationTest {
- 
-         Collections.sort(errors);
- 
--        System.out.println(errors.size() + " missing annotation(s):");
-+        StringBuilder builder = new StringBuilder()
-+            .append("There ")
-+            .append(errors.size() != 1 ? "are " : "is ")
-+            .append(errors.size())
-+            .append(" missing annotation")
-+            .append(errors.size() != 1 ? "s:\n" : ":\n");
-+
-         for (String message : errors) {
--            System.out.print("\t");
--            System.out.println(message);
-+            builder.append("\t").append(message).append("\n");
-         }
- 
--        Assert.fail("There " + errors.size() + " are missing annotation(s)");
-+        Assert.fail(builder.toString());
-     }
- 
-     private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException {
-@@ -0,0 +0,0 @@ public class AnnotationTest {
- 
-     private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map<String, ClassNode> allClasses) {
-         // Exclude private, synthetic and deprecated methods
--        if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0) {
-+        if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0 || (method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0) { // Paper - ignore package-private
-             return false;
-         }
- 
-@@ -0,0 +0,0 @@ public class AnnotationTest {
-         return true;
-     }
- 
--    private static boolean isWellAnnotated(@Nullable List<AnnotationNode> annotations) {
-+    private static boolean isWellAnnotated(@Nullable List<? extends AnnotationNode> annotations) { // Paper
-         if (annotations == null) {
-             return false;
-         }
diff --git a/patches/api/Remove-deadlock-risk-in-firing-async-events.patch b/patches/api/Remove-deadlock-risk-in-firing-async-events.patch
index 5577144752..b41013e8f4 100644
--- a/patches/api/Remove-deadlock-risk-in-firing-async-events.patch
+++ b/patches/api/Remove-deadlock-risk-in-firing-async-events.patch
@@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/test/java/org/bukkit/plugin/PluginManagerTest.java
 +++ b/src/test/java/org/bukkit/plugin/PluginManagerTest.java
 @@ -0,0 +0,0 @@ public class PluginManagerTest {
-     private static final PluginManager pm = TestServer.getInstance().getPluginManager();
+     private static final PluginManager pm = org.bukkit.Bukkit.getServer().getPluginManager(); // Paper
  
      private final MutableObject store = new MutableObject();
 -
diff --git a/patches/api/Test-changes.patch b/patches/api/Test-changes.patch
new file mode 100644
index 0000000000..b7039e17b4
--- /dev/null
+++ b/patches/api/Test-changes.patch
@@ -0,0 +1,478 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Shane Freeder <theboyetronic@gmail.com>
+Date: Sun, 17 Mar 2019 23:04:30 +0000
+Subject: [PATCH] Test changes
+
+- convert to mockito for mocking of types
+- Allow use of TYPE_USE annotations
+- Ignore package-private methods for nullability annotations
+- Add excludes for classes which don't pass
+
+Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
+
+diff --git a/build.gradle.kts b/build.gradle.kts
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/build.gradle.kts
++++ b/build.gradle.kts
+@@ -0,0 +0,0 @@ dependencies {
+     compileOnlyApi(checkerQual)
+     testCompileOnly(checkerQual)
+     // Paper end
++    testImplementation("org.mockito:mockito-core:4.9.0") // Paper - add mockito
+ 
+     testImplementation("org.apache.commons:commons-lang3:3.12.0")
+     testImplementation("junit:junit:4.13.2")
+diff --git a/src/test/java/io/papermc/paper/testing/EmptyRegistry.java b/src/test/java/io/papermc/paper/testing/EmptyRegistry.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/testing/EmptyRegistry.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.testing;
++
++import java.util.Collections;
++import java.util.Iterator;
++import org.bukkit.Keyed;
++import org.bukkit.NamespacedKey;
++import org.bukkit.Registry;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++public record EmptyRegistry() implements Registry<Keyed> {
++
++    @NotNull
++    @Override
++    public Iterator<Keyed> iterator() {
++        return Collections.emptyIterator();
++    }
++
++    @Override
++    public @Nullable Keyed get(@NotNull final NamespacedKey key) {
++        return null;
++    }
++}
+diff --git a/src/test/java/io/papermc/paper/testing/EmptyTag.java b/src/test/java/io/papermc/paper/testing/EmptyTag.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/testing/EmptyTag.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.testing;
++
++import java.util.Collections;
++import java.util.Set;
++import org.bukkit.Keyed;
++import org.bukkit.NamespacedKey;
++import org.bukkit.Tag;
++import org.jetbrains.annotations.NotNull;
++
++public record EmptyTag(NamespacedKey key) implements Tag<Keyed> {
++
++    @SuppressWarnings("deprecation")
++    public EmptyTag() {
++        this(NamespacedKey.randomKey());
++    }
++
++    @Override
++    public @NotNull NamespacedKey getKey() {
++        return this.key;
++    }
++
++    @Override
++    public boolean isTagged(@NotNull final Keyed item) {
++        return false;
++    }
++
++    @Override
++    public @NotNull Set<Keyed> getValues() {
++        return Collections.emptySet();
++    }
++}
+diff --git a/src/test/java/io/papermc/paper/testing/TestServer.java b/src/test/java/io/papermc/paper/testing/TestServer.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/testing/TestServer.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.testing;
++
++import java.util.logging.Logger;
++import org.bukkit.Bukkit;
++import org.bukkit.NamespacedKey;
++import org.bukkit.Server;
++import org.bukkit.command.SimpleCommandMap;
++import org.bukkit.plugin.PluginManager;
++import org.bukkit.plugin.SimplePluginManager;
++
++import static org.mockito.ArgumentMatchers.anyString;
++import static org.mockito.Mockito.any;
++import static org.mockito.Mockito.mock;
++import static org.mockito.Mockito.when;
++
++public final class TestServer {
++
++    @SuppressWarnings("removal")
++    public static void setup() {
++        //noinspection ConstantValue
++        if (Bukkit.getServer() != null) {
++            return;
++        }
++
++        final Server dummyServer = mock(Server.class);
++
++        final Logger logger = Logger.getLogger(TestServer.class.getCanonicalName());
++        when(dummyServer.getLogger()).thenReturn(logger);
++        when(dummyServer.getName()).thenReturn(TestServer.class.getSimpleName());
++        when(dummyServer.getVersion()).thenReturn("Version_" + TestServer.class.getPackage().getImplementationVersion());
++        when(dummyServer.getBukkitVersion()).thenReturn("BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion());
++
++
++        final Thread currentThread = Thread.currentThread();
++        when(dummyServer.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread));
++
++        when(dummyServer.getTag(anyString(), any(NamespacedKey.class), any())).thenAnswer(ignored -> new EmptyTag());
++
++        final PluginManager pluginManager = new SimplePluginManager(dummyServer, new SimpleCommandMap(dummyServer));
++        when(dummyServer.getPluginManager()).thenReturn(pluginManager);
++
++        when(dummyServer.getRegistry(any())).thenAnswer(ignored -> new EmptyRegistry());
++        when(dummyServer.getScoreboardCriteria(anyString())).thenReturn(null);
++
++        Bukkit.setServer(dummyServer);
++    }
++
++}
+diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/test/java/org/bukkit/AnnotationTest.java
++++ b/src/test/java/org/bukkit/AnnotationTest.java
+@@ -0,0 +0,0 @@ public class AnnotationTest {
+         "org/bukkit/util/io/Wrapper",
+         "org/bukkit/plugin/java/PluginClassLoader",
+         // Generic functional interface
+-        "org/bukkit/util/Consumer"
++        "org/bukkit/util/Consumer",
++        // Paper start
++        // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull
++        "co/aikar/timings/TimingHistory$2",
++        "co/aikar/timings/TimingHistory$2$1",
++        "co/aikar/timings/TimingHistory$2$1$1",
++        "co/aikar/timings/TimingHistory$2$1$2",
++        "co/aikar/timings/TimingHistory$3",
++        "co/aikar/timings/TimingHistory$4",
++        "co/aikar/timings/TimingHistoryEntry$1"
++        // Paper end
+     };
+ 
+     @Test
+@@ -0,0 +0,0 @@ public class AnnotationTest {
+                 }
+ 
+                 if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) {
++                    // Paper start - Allow use of TYPE_USE annotations
++                    boolean warn = true;
++                    if (isWellAnnotated(method.visibleTypeAnnotations)) {
++                        warn = false;
++                    } else if (method.invisibleTypeAnnotations != null) {
++                        dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) {
++                            final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef);
++                            if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) {
++                                warn = false;
++                                break dance; // cha cha real smooth
++                            }
++                        }
++                    }
++                    if (warn)
++                    // Paper end
+                     warn(errors, clazz, method, "return value");
+                 }
+ 
+                 Type[] paramTypes = Type.getArgumentTypes(method.desc);
+                 List<ParameterNode> parameters = method.parameters;
+ 
++                dancing: // Paper
+                 for (int i = 0; i < paramTypes.length; i++) {
+                     if (mustBeAnnotated(paramTypes[i]) ^ isWellAnnotated(method.invisibleParameterAnnotations == null ? null : method.invisibleParameterAnnotations[i])) {
++                        // Paper start
++                        if (method.invisibleTypeAnnotations != null) {
++                            for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) {
++                                final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef);
++                                if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) {
++                                    continue dancing;
++                                }
++                            }
++                        }
++                        // Paper end - Allow use of TYPE_USE annotations
+                         ParameterNode paramNode = parameters == null ? null : parameters.get(i);
+                         String paramName = paramNode == null ? null : paramNode.name;
+ 
+@@ -0,0 +0,0 @@ public class AnnotationTest {
+ 
+         Collections.sort(errors);
+ 
+-        System.out.println(errors.size() + " missing annotation(s):");
++        StringBuilder builder = new StringBuilder()
++            .append("There ")
++            .append(errors.size() != 1 ? "are " : "is ")
++            .append(errors.size())
++            .append(" missing annotation")
++            .append(errors.size() != 1 ? "s:\n" : ":\n");
++
+         for (String message : errors) {
+-            System.out.print("\t");
+-            System.out.println(message);
++            builder.append("\t").append(message).append("\n");
+         }
+ 
+-        Assert.fail("There " + errors.size() + " are missing annotation(s)");
++        Assert.fail(builder.toString());
+     }
+ 
+     private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException {
+@@ -0,0 +0,0 @@ public class AnnotationTest {
+ 
+     private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map<String, ClassNode> allClasses) {
+         // Exclude private, synthetic and deprecated methods
+-        if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0) {
++        if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0 || (method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0) { // Paper - ignore package-private
+             return false;
+         }
+ 
+@@ -0,0 +0,0 @@ public class AnnotationTest {
+         return true;
+     }
+ 
+-    private static boolean isWellAnnotated(@Nullable List<AnnotationNode> annotations) {
++    private static boolean isWellAnnotated(@Nullable List<? extends AnnotationNode> annotations) { // Paper
+         if (annotations == null) {
+             return false;
+         }
+diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java
+deleted file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- a/src/test/java/org/bukkit/TestServer.java
++++ /dev/null
+@@ -0,0 +0,0 @@
+-package org.bukkit;
+-
+-import com.google.common.collect.ImmutableMap;
+-import java.lang.reflect.InvocationHandler;
+-import java.lang.reflect.Method;
+-import java.lang.reflect.Proxy;
+-import java.util.Iterator;
+-import java.util.Map;
+-import java.util.logging.Logger;
+-import org.bukkit.command.SimpleCommandMap;
+-import org.bukkit.plugin.PluginManager;
+-import org.bukkit.plugin.SimplePluginManager;
+-import org.jetbrains.annotations.NotNull;
+-import org.jetbrains.annotations.Nullable;
+-
+-public final class TestServer implements InvocationHandler {
+-    private static interface MethodHandler {
+-        Object handle(TestServer server, Object[] args);
+-    }
+-
+-    private static final Map<Method, MethodHandler> methods;
+-
+-    static {
+-        try {
+-            ImmutableMap.Builder<Method, MethodHandler> methodMap = ImmutableMap.builder();
+-            methodMap.put(
+-                    Server.class.getMethod("isPrimaryThread"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return Thread.currentThread().equals(server.creatingThread);
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getPluginManager"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return server.pluginManager;
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getLogger"),
+-                    new MethodHandler() {
+-                        final Logger logger = Logger.getLogger(TestServer.class.getCanonicalName());
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return logger;
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getName"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return TestServer.class.getSimpleName();
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getVersion"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return "Version_" + TestServer.class.getPackage().getImplementationVersion();
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getBukkitVersion"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return "BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion();
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getRegistry", Class.class),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            return new Registry() {
+-                                @NotNull
+-                                @Override
+-                                public Iterator iterator() {
+-                                    return null;
+-                                }
+-
+-                                @Nullable
+-                                @Override
+-                                public Keyed get(@NotNull NamespacedKey key) {
+-                                    return null;
+-                                }
+-                            };
+-                        }
+-                    }
+-                );
+-            methodMap.put(
+-                    Server.class.getMethod("getScoreboardCriteria", String.class),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(TestServer server, Object[] args) {
+-                            // Does not need to return anything. Exists solely to test CriteriaTest which has static init fields
+-                            return null;
+-                        }
+-                    }
+-                );
+-            methods = methodMap.build();
+-
+-            TestServer server = new TestServer();
+-            Server instance = Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(server);
+-            Bukkit.setServer(instance);
+-            server.pluginManager = new SimplePluginManager(instance, new SimpleCommandMap(instance));
+-        } catch (Throwable t) {
+-            throw new Error(t);
+-        }
+-    }
+-
+-    private Thread creatingThread = Thread.currentThread();
+-    private PluginManager pluginManager;
+-    private TestServer() {};
+-
+-    public static Server getInstance() {
+-        return Bukkit.getServer();
+-    }
+-
+-    @Override
+-    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/TestWorld.java b/src/test/java/org/bukkit/TestWorld.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/test/java/org/bukkit/TestWorld.java
++++ b/src/test/java/org/bukkit/TestWorld.java
+@@ -0,0 +0,0 @@ public final class TestWorld implements InvocationHandler {
+ 
+     static {
+         try {
+-            TestServer.getInstance();
++            io.papermc.paper.testing.TestServer.setup(); // Paper
+ 
+             ImmutableMap.Builder<Method, MethodHandler> methodMap = ImmutableMap.builder();
+             methodMap.put(
+diff --git a/src/test/java/org/bukkit/event/SyntheticEventTest.java b/src/test/java/org/bukkit/event/SyntheticEventTest.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/test/java/org/bukkit/event/SyntheticEventTest.java
++++ b/src/test/java/org/bukkit/event/SyntheticEventTest.java
+@@ -0,0 +0,0 @@
+ package org.bukkit.event;
+ 
+-import org.bukkit.TestServer;
+ import org.bukkit.plugin.PluginLoader;
+ import org.bukkit.plugin.SimplePluginManager;
+ import org.bukkit.plugin.TestPlugin;
+@@ -0,0 +0,0 @@ public class SyntheticEventTest {
+     @SuppressWarnings("deprecation")
+     @Test
+     public void test() {
+-        final JavaPluginLoader loader = new JavaPluginLoader(TestServer.getInstance());
++        io.papermc.paper.testing.TestServer.setup(); // Paper
++        final JavaPluginLoader loader = new JavaPluginLoader(org.bukkit.Bukkit.getServer()); // Paper
+         TestPlugin plugin = new TestPlugin(getClass().getName()) {
+             @Override
+             public PluginLoader getPluginLoader() {
+                 return loader;
+             }
+         };
+-        SimplePluginManager pluginManager = new SimplePluginManager(TestServer.getInstance(), null);
++        SimplePluginManager pluginManager = new SimplePluginManager(org.bukkit.Bukkit.getServer(), null); // Paper
+ 
+         TestEvent event = new TestEvent(false);
+         Impl impl = new Impl();
+diff --git a/src/test/java/org/bukkit/plugin/PluginManagerTest.java b/src/test/java/org/bukkit/plugin/PluginManagerTest.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/test/java/org/bukkit/plugin/PluginManagerTest.java
++++ b/src/test/java/org/bukkit/plugin/PluginManagerTest.java
+@@ -0,0 +0,0 @@ package org.bukkit.plugin;
+ 
+ import static org.hamcrest.Matchers.*;
+ import static org.junit.Assert.*;
+-import org.bukkit.TestServer;
+ import org.bukkit.event.Event;
+ import org.bukkit.event.TestEvent;
+ import org.bukkit.permissions.Permission;
+@@ -0,0 +0,0 @@ public class PluginManagerTest {
+         volatile Object value = null;
+     }
+ 
+-    private static final PluginManager pm = TestServer.getInstance().getPluginManager();
++    private static final PluginManager pm = org.bukkit.Bukkit.getServer().getPluginManager(); // Paper
+ 
+     private final MutableObject store = new MutableObject();
+ 
+diff --git a/src/test/java/org/bukkit/scoreboard/CriteriaTest.java b/src/test/java/org/bukkit/scoreboard/CriteriaTest.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/test/java/org/bukkit/scoreboard/CriteriaTest.java
++++ b/src/test/java/org/bukkit/scoreboard/CriteriaTest.java
+@@ -0,0 +0,0 @@ package org.bukkit.scoreboard;
+ 
+ import org.bukkit.Material;
+ import org.bukkit.Statistic;
+-import org.bukkit.TestServer;
+ import org.bukkit.entity.EntityType;
+ import org.junit.Assert;
+ import org.junit.Test;
+@@ -0,0 +0,0 @@ public class CriteriaTest {
+ 
+     @Test
+     public void testStatistic() {
+-        TestServer.getInstance();
++        io.papermc.paper.testing.TestServer.setup(); // Paper
+ 
+         Assert.assertThrows(IllegalArgumentException.class, () -> Criteria.statistic(Statistic.AVIATE_ONE_CM, Material.STONE)); // Generic statistic with block
+         Assert.assertThrows(IllegalArgumentException.class, () -> Criteria.statistic(Statistic.AVIATE_ONE_CM, EntityType.CREEPER)); // Generic statistic with entity type
diff --git a/patches/server/Added-missing-default-perms-for-commands.patch b/patches/server/Added-missing-default-perms-for-commands.patch
index d8cb1b19d9..f76c09264e 100644
--- a/patches/server/Added-missing-default-perms-for-commands.patch
+++ b/patches/server/Added-missing-default-perms-for-commands.patch
@@ -170,38 +170,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        }
 +    }
 +}
-diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/test/java/org/bukkit/support/DummyServer.java
-+++ b/src/test/java/org/bukkit/support/DummyServer.java
-@@ -0,0 +0,0 @@ public final class DummyServer implements InvocationHandler {
-                         }
-                     }
-             );
--            Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer()));
-+            // Paper start - modeled off of TestServer in the API tests module
-+            methods.put(
-+                Server.class.getMethod("getPluginManager"),
-+                new MethodHandler() {
-+                    @Override
-+                    public Object handle(DummyServer server, Object[] args) {
-+                        return server.pluginManager;
-+                    }
-+                }
-+            );
-+            DummyServer server = new DummyServer();
-+            Server instance = Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(server);
-+            Bukkit.setServer(instance);
-+            server.pluginManager = new org.bukkit.plugin.SimplePluginManager(instance, new org.bukkit.command.SimpleCommandMap(instance));
-+            // Paper end
-         } catch (Throwable t) {
-             throw new Error(t);
-         }
-@@ -0,0 +0,0 @@ public final class DummyServer implements InvocationHandler {
- 
-     private DummyServer() {};
- 
-+    private org.bukkit.plugin.PluginManager pluginManager; // Paper
-     @Override
-     public Object invoke(Object proxy, Method method, Object[] args) {
-         MethodHandler handler = DummyServer.methods.get(method);
diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
index cf0447c3f1..9e56a8c403 100644
--- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
+++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
@@ -17,7 +17,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      // Paper end
      implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion
      implementation("org.ow2.asm:asm:9.3")
-     implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation
+@@ -0,0 +0,0 @@ dependencies {
+     testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito
      implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files
      implementation("commons-lang:commons-lang:2.6")
 +    implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
diff --git a/patches/server/Paper-config-files.patch b/patches/server/Paper-config-files.patch
index 95b2204dba..30d2cec6f7 100644
--- a/patches/server/Paper-config-files.patch
+++ b/patches/server/Paper-config-files.patch
@@ -18,9 +18,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/build.gradle.kts
 +++ b/build.gradle.kts
 @@ -0,0 +0,0 @@ dependencies {
-     implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion
      implementation("org.ow2.asm:asm:9.3")
      implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation
+     testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito
 +    implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files
      implementation("commons-lang:commons-lang:2.6")
      runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")
@@ -4664,8 +4664,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/test/java/org/bukkit/support/AbstractTestingBase.java
 +++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java
 @@ -0,0 +0,0 @@ public abstract class AbstractTestingBase {
+         BIOMES = REGISTRY_CUSTOM.registryOrThrow(Registries.BIOME);
  
-         DummyServer.setup();
          DummyEnchantments.setup();
 +        io.papermc.paper.configuration.GlobalConfigTestingBase.setupGlobalConfigForTest(); // Paper
  
diff --git a/patches/server/Test-changes.patch b/patches/server/Test-changes.patch
new file mode 100644
index 0000000000..9c8c50be8e
--- /dev/null
+++ b/patches/server/Test-changes.patch
@@ -0,0 +1,280 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <jake.m.potrebic@gmail.com>
+Date: Mon, 13 Feb 2023 14:14:56 -0800
+Subject: [PATCH] Test changes
+
+
+diff --git a/build.gradle.kts b/build.gradle.kts
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/build.gradle.kts
++++ b/build.gradle.kts
+@@ -0,0 +0,0 @@ dependencies {
+     implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion
+     implementation("org.ow2.asm:asm:9.3")
+     implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation
++    testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito
+     implementation("commons-lang:commons-lang:2.6")
+     runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")
+     runtimeOnly("mysql:mysql-connector-java:8.0.29")
+diff --git a/src/test/java/io/papermc/paper/testing/DummyServer.java b/src/test/java/io/papermc/paper/testing/DummyServer.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/testing/DummyServer.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.testing;
++
++import java.util.logging.Logger;
++import org.bukkit.Bukkit;
++import org.bukkit.Material;
++import org.bukkit.NamespacedKey;
++import org.bukkit.Server;
++import org.bukkit.command.SimpleCommandMap;
++import org.bukkit.craftbukkit.CraftRegistry;
++import org.bukkit.craftbukkit.block.data.CraftBlockData;
++import org.bukkit.craftbukkit.inventory.CraftItemFactory;
++import org.bukkit.craftbukkit.util.CraftMagicNumbers;
++import org.bukkit.craftbukkit.util.CraftNamespacedKey;
++import org.bukkit.plugin.PluginManager;
++import org.bukkit.plugin.SimplePluginManager;
++import org.bukkit.support.AbstractTestingBase;
++
++import static org.mockito.Mockito.any;
++import static org.mockito.Mockito.mock;
++import static org.mockito.Mockito.when;
++
++public final class DummyServer {
++
++    @SuppressWarnings({"deprecation", "removal"})
++    public static void setup() {
++        //noinspection ConstantValue
++        if (Bukkit.getServer() != null) {
++            return;
++        }
++
++        final Server dummyServer = mock(Server.class);
++
++        final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName());
++        when(dummyServer.getLogger()).thenReturn(logger);
++        when(dummyServer.getName()).thenReturn(DummyServer.class.getSimpleName());
++        when(dummyServer.getVersion()).thenReturn("Version_" + DummyServer.class.getPackage().getImplementationVersion());
++        when(dummyServer.getBukkitVersion()).thenReturn("BukkitVersion_" + DummyServer.class.getPackage().getImplementationVersion());
++
++        final Thread currentThread = Thread.currentThread();
++        when(dummyServer.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread));
++
++        when(dummyServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
++
++        when(dummyServer.getUnsafe()).thenAnswer(ignored -> CraftMagicNumbers.INSTANCE); // lambda for lazy load
++
++        when(dummyServer.createBlockData(any(Material.class))).thenAnswer(invocation -> {
++            return CraftBlockData.newData(invocation.getArgument(0, Material.class), null);
++        });
++
++        when(dummyServer.getLootTable(any(NamespacedKey.class))).thenAnswer(invocation -> {
++            final NamespacedKey key = invocation.getArgument(0, NamespacedKey.class);
++            return new org.bukkit.craftbukkit.CraftLootTable(key, AbstractTestingBase.DATA_PACK.getLootTables().get(CraftNamespacedKey.toMinecraft(key)));
++        });
++
++        when(dummyServer.getRegistry(any())).thenAnswer(invocation -> {
++            // LazyRegistry because the vanilla data hasn't been bootstrapped yet.
++            return new LazyRegistry(() -> CraftRegistry.createRegistry(invocation.getArgument(0, Class.class), AbstractTestingBase.REGISTRY_CUSTOM));
++        });
++
++        final PluginManager pluginManager = new SimplePluginManager(dummyServer, new SimpleCommandMap(dummyServer));
++        when(dummyServer.getPluginManager()).thenReturn(pluginManager);
++
++        Bukkit.setServer(dummyServer);
++
++    }
++}
+diff --git a/src/test/java/io/papermc/paper/testing/LazyRegistry.java b/src/test/java/io/papermc/paper/testing/LazyRegistry.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/test/java/io/papermc/paper/testing/LazyRegistry.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.testing;
++
++import java.util.Iterator;
++import java.util.function.Supplier;
++import org.bukkit.Keyed;
++import org.bukkit.NamespacedKey;
++import org.bukkit.Registry;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++public record LazyRegistry(Supplier<Registry<Keyed>> supplier) implements Registry<Keyed> {
++
++    @NotNull
++    @Override
++    public Iterator<Keyed> iterator() {
++        return this.supplier().get().iterator();
++    }
++
++    @Override
++    public @Nullable Keyed get(@NotNull final NamespacedKey key) {
++        return this.supplier().get().get(key);
++    }
++}
+diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/test/java/org/bukkit/support/AbstractTestingBase.java
++++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java
+@@ -0,0 +0,0 @@ package org.bukkit.support;
+ 
+ import com.google.common.collect.ImmutableList;
+ import com.google.common.util.concurrent.MoreExecutors;
+-import java.util.Collections;
+ import java.util.List;
+ import net.minecraft.SharedConstants;
+ import net.minecraft.commands.Commands;
+@@ -0,0 +0,0 @@ public abstract class AbstractTestingBase {
+     public static final Registry<Biome> BIOMES;
+ 
+     static {
++        io.papermc.paper.testing.DummyServer.setup(); // Paper
+         SharedConstants.tryDetectVersion();
+         Bootstrap.bootStrap();
+         // Set up resource manager
+@@ -0,0 +0,0 @@ public abstract class AbstractTestingBase {
+         // Biome shortcut
+         BIOMES = REGISTRY_CUSTOM.registryOrThrow(Registries.BIOME);
+ 
+-        DummyServer.setup();
+         DummyEnchantments.setup();
+ 
+         ImmutableList.Builder<Material> builder = ImmutableList.builder();
+diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java
+deleted file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- a/src/test/java/org/bukkit/support/DummyServer.java
++++ /dev/null
+@@ -0,0 +0,0 @@
+-package org.bukkit.support;
+-
+-import java.lang.reflect.InvocationHandler;
+-import java.lang.reflect.Method;
+-import java.lang.reflect.Proxy;
+-import java.util.HashMap;
+-import java.util.logging.Logger;
+-import org.bukkit.Bukkit;
+-import org.bukkit.Material;
+-import org.bukkit.NamespacedKey;
+-import org.bukkit.Server;
+-import org.bukkit.craftbukkit.CraftLootTable;
+-import org.bukkit.craftbukkit.CraftRegistry;
+-import org.bukkit.craftbukkit.block.data.CraftBlockData;
+-import org.bukkit.craftbukkit.inventory.CraftItemFactory;
+-import org.bukkit.craftbukkit.util.CraftMagicNumbers;
+-import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+-import org.bukkit.craftbukkit.util.Versioning;
+-
+-public final class DummyServer implements InvocationHandler {
+-    private static interface MethodHandler {
+-        Object handle(DummyServer server, Object[] args);
+-    }
+-    private static final HashMap<Method, MethodHandler> methods = new HashMap<Method, MethodHandler>();
+-    static {
+-        try {
+-            methods.put(
+-                    Server.class.getMethod("getItemFactory"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return CraftItemFactory.instance();
+-                        }
+-                    }
+-                );
+-            methods.put(
+-                    Server.class.getMethod("getName"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return DummyServer.class.getName();
+-                        }
+-                    }
+-                );
+-            methods.put(
+-                    Server.class.getMethod("getVersion"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return DummyServer.class.getPackage().getImplementationVersion();
+-                        }
+-                    }
+-                );
+-            methods.put(
+-                    Server.class.getMethod("getBukkitVersion"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return Versioning.getBukkitVersion();
+-                        }
+-                    }
+-                );
+-            methods.put(
+-                    Server.class.getMethod("getLogger"),
+-                    new MethodHandler() {
+-                        final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName());
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return logger;
+-                        }
+-                    }
+-                );
+-            methods.put(
+-                    Server.class.getMethod("getUnsafe"),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return CraftMagicNumbers.INSTANCE;
+-                        }
+-                    }
+-                );
+-            methods.put(
+-                    Server.class.getMethod("createBlockData", Material.class),
+-                    new MethodHandler() {
+-                        final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName());
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return CraftBlockData.newData((Material) args[0], null);
+-                        }
+-                    }
+-                );
+-            methods.put(Server.class.getMethod("getLootTable", NamespacedKey.class),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            NamespacedKey key = (NamespacedKey) args[0];
+-                            return new CraftLootTable(key, AbstractTestingBase.DATA_PACK.getLootTables().get(CraftNamespacedKey.toMinecraft(key)));
+-                        }
+-                    }
+-                );
+-            methods.put(Server.class.getMethod("getRegistry", Class.class),
+-                    new MethodHandler() {
+-                        @Override
+-                        public Object handle(DummyServer server, Object[] args) {
+-                            return CraftRegistry.createRegistry((Class) args[0], AbstractTestingBase.REGISTRY_CUSTOM);
+-                        }
+-                    }
+-            );
+-            Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer()));
+-        } catch (Throwable t) {
+-            throw new Error(t);
+-        }
+-    }
+-
+-    public static void setup() {}
+-
+-    private DummyServer() {};
+-
+-    @Override
+-    public Object invoke(Object proxy, Method method, Object[] args) {
+-        MethodHandler handler = DummyServer.methods.get(method);
+-        if (handler != null) {
+-            return handler.handle(this, args);
+-        }
+-        throw new UnsupportedOperationException(String.valueOf(method));
+-    }
+-}