Skip to content

Commit ed272c8

Browse files
committed
Ensure tests run inside phase tracker phase
1 parent dbc1207 commit ed272c8

File tree

10 files changed

+130
-12
lines changed

10 files changed

+130
-12
lines changed

forge/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ tasks {
436436
jvmArgs("-Dsponge.test.args=" + runServer.args.joinToString(" "))
437437
jvmArgs("-Dsponge.jacoco.packages=org.spongepowered")
438438
jvmArgs("-Djunit.platform.launcher.interceptors.enabled=true")
439+
jvmArgs("-Djunit.jupiter.extensions.autodetection.enabled=true")
439440
workingDir = layout.buildDirectory.dir("test-run").get().asFile
440441

441442
doFirst {

neoforge/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ tasks {
411411
jvmArgs("-Dsponge.test.args=" + runServer.get().args!!.joinToString(" "))
412412
jvmArgs("-Dsponge.jacoco.packages=org.spongepowered")
413413
jvmArgs("-Djunit.platform.launcher.interceptors.enabled=true")
414+
jvmArgs("-Djunit.jupiter.extensions.autodetection.enabled=true")
414415
workingDir = layout.buildDirectory.dir("test-run").get().asFile
415416

416417
doFirst {

src/main/java/org/spongepowered/common/bridge/server/MinecraftServerBridge.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,8 @@ public interface MinecraftServerBridge {
5757
default void bridge$tickServer(int ticks) {
5858
throw new UnsupportedOperationException("Cannot trigger manual server tick outside test environment");
5959
}
60+
61+
default boolean bridge$insideTestEnvironment() {
62+
return false;
63+
}
6064
}

src/main/java/org/spongepowered/common/event/tracking/PhaseTracker.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,17 @@ public static PhaseTracker getInstance() {
111111
return PhaseTracker.CLIENT;
112112
}
113113

114-
return PhaseTracker.SPINOFF_TRACKERS.computeIfAbsent(current, (thread) -> {
115-
try {
116-
final PhaseTracker phaseTracker = new PhaseTracker();
117-
phaseTracker.setThread(thread);
118-
return phaseTracker;
119-
} catch (final IllegalAccessException e) {
120-
throw new RuntimeException("Unable to create a new PhaseTracker for Thread: " + thread, e);
121-
}
122-
});
114+
return PhaseTracker.SPINOFF_TRACKERS.computeIfAbsent(current, PhaseTracker::createNew);
115+
}
116+
117+
public static PhaseTracker createNew(final Thread thread) {
118+
try {
119+
final PhaseTracker phaseTracker = new PhaseTracker();
120+
phaseTracker.setThread(thread);
121+
return phaseTracker;
122+
} catch (final IllegalAccessException e) {
123+
throw new RuntimeException("Unable to create a new PhaseTracker for Thread: " + thread, e);
124+
}
123125
}
124126

125127
/**

src/mixins/java/org/spongepowered/common/mixin/test/server/MinecraftServerMixin_Test.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,9 @@ private boolean haveTime() {
119119
this.waitUntilNextTick();
120120
}
121121
}
122+
123+
@Override
124+
public boolean bridge$insideTestEnvironment() {
125+
return true;
126+
}
122127
}

src/mixins/java/org/spongepowered/common/mixin/tracker/server/MinecraftServerMixin_Tracker.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.spongepowered.asm.mixin.injection.At;
3838
import org.spongepowered.asm.mixin.injection.Inject;
3939
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
40+
import org.spongepowered.common.bridge.server.MinecraftServerBridge;
4041
import org.spongepowered.common.bridge.server.TickTaskBridge;
4142
import org.spongepowered.common.event.tracking.CauseTrackerCrashHandler;
4243
import org.spongepowered.common.event.tracking.PhaseContext;
@@ -70,7 +71,9 @@ public abstract class MinecraftServerMixin_Tracker extends BlockableEventLoopMix
7071
context.buildAndSwitch();
7172
original.call(hasTimeLeft);
7273
}
73-
PhaseTracker.getServerInstanceExplicitly().ensureEmpty();
74+
if (!((MinecraftServerBridge) this).bridge$insideTestEnvironment()) {
75+
PhaseTracker.getServerInstanceExplicitly().ensureEmpty();
76+
}
7477
}
7578

7679
@WrapOperation(

src/test/java/org/spongepowered/common/event/tracking/PhaseTrackerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class PhaseTrackerTest {
3535

3636
@Test
3737
public void testPoppingFramePopsCauses() {
38-
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
38+
final PhaseTracker phaseTracker = PhaseTracker.createNew(Thread.currentThread());
3939

4040
// We start by pushing a frame...
4141
CauseStackManager.StackFrame frame1 = phaseTracker.pushCauseFrame();
@@ -60,7 +60,7 @@ public void testPoppingFramePopsCauses() {
6060

6161
@Test
6262
public void testPoppingFrameRemovesFrameContexts() {
63-
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
63+
final PhaseTracker phaseTracker = PhaseTracker.createNew(Thread.currentThread());
6464

6565
String cmd1 = "one";
6666
String cmd2 = "two";
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* This file is part of Sponge, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package org.spongepowered.common.test;
26+
27+
import net.minecraft.server.MinecraftServer;
28+
import org.checkerframework.checker.nullness.qual.NonNull;
29+
import org.junit.jupiter.api.extension.DynamicTestInvocationContext;
30+
import org.junit.jupiter.api.extension.ExtensionContext;
31+
import org.junit.jupiter.api.extension.InvocationInterceptor;
32+
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
33+
import org.spongepowered.api.Sponge;
34+
import org.spongepowered.common.event.tracking.PhaseContext;
35+
import org.spongepowered.common.event.tracking.PhaseTracker;
36+
import org.spongepowered.common.event.tracking.phase.tick.TickPhase;
37+
38+
import java.lang.reflect.Constructor;
39+
import java.lang.reflect.Method;
40+
41+
public final class TestInvocationInterceptor implements InvocationInterceptor {
42+
43+
@Override
44+
public <T> T interceptTestClassConstructor(final Invocation<T> invocation, final ReflectiveInvocationContext<Constructor<T>> invocationContext, final ExtensionContext extensionContext) throws Throwable {
45+
return this.intercept(invocation);
46+
}
47+
48+
@Override
49+
public void interceptBeforeAllMethod(final Invocation<Void> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
50+
this.intercept(invocation);
51+
}
52+
53+
@Override
54+
public void interceptBeforeEachMethod(final Invocation<Void> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
55+
this.intercept(invocation);
56+
}
57+
58+
@Override
59+
public void interceptTestMethod(final Invocation<Void> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
60+
this.intercept(invocation);
61+
}
62+
63+
@Override
64+
public <T> T interceptTestFactoryMethod(final Invocation<T> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
65+
return this.intercept(invocation);
66+
}
67+
68+
@Override
69+
public void interceptTestTemplateMethod(final Invocation<Void> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
70+
this.intercept(invocation);
71+
}
72+
73+
@Override
74+
public void interceptDynamicTest(final Invocation<Void> invocation, final DynamicTestInvocationContext invocationContext, final ExtensionContext extensionContext) throws Throwable {
75+
this.intercept(invocation);
76+
}
77+
78+
@Override
79+
public void interceptAfterAllMethod(final Invocation<Void> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
80+
this.intercept(invocation);
81+
}
82+
83+
@Override
84+
public void interceptAfterEachMethod(final Invocation<Void> invocation, final ReflectiveInvocationContext<Method> invocationContext, final ExtensionContext extensionContext) throws Throwable {
85+
this.intercept(invocation);
86+
}
87+
88+
private <T> T intercept(final Invocation<T> invocation) throws Throwable {
89+
try (
90+
final PhaseContext<@NonNull ?> context = TickPhase.Tick.SERVER_TICK
91+
.createPhaseContext(PhaseTracker.getServerInstanceExplicitly())
92+
.server((MinecraftServer) Sponge.server())
93+
) {
94+
context.buildAndSwitch();
95+
return invocation.proceed();
96+
} finally {
97+
PhaseTracker.getServerInstanceExplicitly().ensureEmpty();
98+
}
99+
}
100+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.spongepowered.common.test.TestInvocationInterceptor

vanilla/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ tasks {
518518
jvmArgs("-Dsponge.test.args=" + runServer.allArguments().joinToString(" "))
519519
jvmArgs("-Dsponge.jacoco.packages=org.spongepowered")
520520
jvmArgs("-Djunit.platform.launcher.interceptors.enabled=true")
521+
jvmArgs("-Djunit.jupiter.extensions.autodetection.enabled=true")
521522
workingDir = layout.buildDirectory.dir("test-run").get().asFile
522523

523524
doFirst {

0 commit comments

Comments
 (0)