Skip to content

Commit

Permalink
Move client auto tests to new module fabric-client-gametest-api-v1
Browse files Browse the repository at this point in the history
  • Loading branch information
Earthcomputer committed Dec 10, 2024
1 parent f906699 commit 9af40ea
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 148 deletions.
16 changes: 12 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ loom {
autoTestClient {
inherit testmodClient
name "Auto Test Client"
vmArg "-Dfabric.autoTest"
vmArg "-Dfabric.client.gametest"
vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail"
vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail"
}
Expand Down Expand Up @@ -498,6 +498,9 @@ import net.fabricmc.loom.util.Platform
// This is very far beyond loom's API if you copy this, you're on your own.
tasks.register('runProductionAutoTestClient', JavaExec) {
dependsOn remapJar, remapTestmodJar, downloadAssets
afterEvaluate {
dependsOn project(':fabric-client-gametest-api-v1').remapJar
}
classpath.from configurations.productionRuntime
mainClass = "net.fabricmc.loader.impl.launch.knot.KnotClient"
workingDir = file("run")
Expand All @@ -518,9 +521,11 @@ tasks.register('runProductionAutoTestClient', JavaExec) {
)
}

afterEvaluate {
jvmArgs "-Dfabric.addMods=${remapJar.archiveFile.get().asFile.absolutePath}${File.pathSeparator}${remapTestmodJar.archiveFile.get().asFile.absolutePath}${File.pathSeparator}${project(':fabric-client-gametest-api-v1').remapJar.archiveFile.get().asFile.absolutePath}"
}
jvmArgs(
"-Dfabric.addMods=${remapJar.archiveFile.get().asFile.absolutePath}${File.pathSeparator}${remapTestmodJar.archiveFile.get().asFile.absolutePath}",
"-Dfabric.autoTest",
"-Dfabric.gametest.client",
"-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail",
"-Dfabric-tag-conventions-v1.legacyTagWarning=fail"
)
Expand Down Expand Up @@ -726,7 +731,10 @@ subprojects.each {
}

// These modules are not included in the fat jar, maven will resolve them via the pom.
def devOnlyModules = ["fabric-gametest-api-v1",]
def devOnlyModules = [
"fabric-client-gametest-api-v1",
"fabric-gametest-api-v1",
]

dependencies {
afterEvaluate {
Expand Down
11 changes: 1 addition & 10 deletions fabric-api-base/src/testmod/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,11 @@
"main": [
"net.fabricmc.fabric.test.base.FabricApiBaseTestInit"
],
"client": [
"net.fabricmc.fabric.test.base.client.FabricApiAutoTestClient"
],
"server": [
"net.fabricmc.fabric.test.base.FabricApiAutoTestServer"
],
"fabric-gametest" : [
"net.fabricmc.fabric.test.base.FabricApiBaseGameTest"
]
},
"mixins": [
{
"config": "fabric-api-base-testmod.client.mixins.json",
"environment": "client"
}
]
}
}
6 changes: 6 additions & 0 deletions fabric-client-gametest-api-v1/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version = getSubprojectVersion(project)

moduleDependencies(project, [
'fabric-api-base',
'fabric-resource-loader-v0'
])
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.fabric.impl.gametest.client;

import java.util.List;
import java.util.Set;

import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;

public class ClientGameTestMixinConfigPlugin implements IMixinConfigPlugin {
private static final boolean ENABLED = System.getProperty("fabric.client.gametest") != null;

@Override
public void onLoad(String mixinPackage) {
}

@Override
public String getRefMapperConfig() {
return null;
}

@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return ENABLED;
}

@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}

@Override
public List<String> getMixins() {
return null;
}

@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}

@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package net.fabricmc.fabric.test.base.client;
package net.fabricmc.fabric.impl.gametest.client;

import java.util.Objects;
import java.util.function.Function;
Expand Down Expand Up @@ -45,9 +45,9 @@
import net.minecraft.client.util.ScreenshotRecorder;
import net.minecraft.text.Text;

import net.fabricmc.fabric.test.base.client.mixin.CyclingButtonWidgetAccessor;
import net.fabricmc.fabric.test.base.client.mixin.ScreenAccessor;
import net.fabricmc.fabric.test.base.client.mixin.TitleScreenAccessor;
import net.fabricmc.fabric.mixin.gametest.client.CyclingButtonWidgetAccessor;
import net.fabricmc.fabric.mixin.gametest.client.ScreenAccessor;
import net.fabricmc.fabric.mixin.gametest.client.TitleScreenAccessor;
import net.fabricmc.loader.api.FabricLoader;

public final class FabricClientTestHelper {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package net.fabricmc.fabric.test.base.client;
package net.fabricmc.fabric.impl.gametest.client;

import java.io.Closeable;
import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package net.fabricmc.fabric.test.base.client;
package net.fabricmc.fabric.impl.gametest.client;

import java.util.concurrent.Phaser;
import java.util.concurrent.Semaphore;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package net.fabricmc.fabric.test.base.client.mixin;
package net.fabricmc.fabric.mixin.gametest.client;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package net.fabricmc.fabric.test.base.client.mixin;
package net.fabricmc.fabric.mixin.gametest.client;

import com.google.common.base.Preconditions;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
Expand All @@ -32,8 +32,7 @@
import net.minecraft.server.SaveLoader;
import net.minecraft.world.level.storage.LevelStorage;

import net.fabricmc.fabric.test.base.client.FabricApiAutoTestClient;
import net.fabricmc.fabric.test.base.client.ThreadingImpl;
import net.fabricmc.fabric.impl.gametest.client.ThreadingImpl;

@Mixin(MinecraftClient.class)
public class MinecraftClientMixin {
Expand All @@ -42,71 +41,63 @@ public class MinecraftClientMixin {

@WrapMethod(method = "run")
private void onRun(Operation<Void> original) {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
if (ThreadingImpl.isClientRunning) {
throw new IllegalStateException("Client is already running");
}

ThreadingImpl.isClientRunning = true;
ThreadingImpl.PHASER.register();
if (ThreadingImpl.isClientRunning) {
throw new IllegalStateException("Client is already running");
}

ThreadingImpl.isClientRunning = true;
ThreadingImpl.PHASER.register();

try {
original.call();
} finally {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
ThreadingImpl.clientCanAcceptTasks = false;
ThreadingImpl.PHASER.arriveAndDeregister();
ThreadingImpl.isClientRunning = false;
}
ThreadingImpl.clientCanAcceptTasks = false;
ThreadingImpl.PHASER.arriveAndDeregister();
ThreadingImpl.isClientRunning = false;
}
}

@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;runTasks()V"))
private void preRunTasks(CallbackInfo ci) {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_SERVER_TASKS);
// server tasks happen here
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_CLIENT_TASKS);
}
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_SERVER_TASKS);
// server tasks happen here
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_CLIENT_TASKS);
}

@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;runTasks()V", shift = At.Shift.AFTER))
private void postRunTasks(CallbackInfo ci) {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
ThreadingImpl.clientCanAcceptTasks = true;
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_TEST);

if (ThreadingImpl.testThread != null) {
while (true) {
try {
ThreadingImpl.CLIENT_SEMAPHORE.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

if (ThreadingImpl.taskToRun != null) {
ThreadingImpl.taskToRun.run();
} else {
break;
}
ThreadingImpl.clientCanAcceptTasks = true;
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_TEST);

if (ThreadingImpl.testThread != null) {
while (true) {
try {
ThreadingImpl.CLIENT_SEMAPHORE.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

if (ThreadingImpl.taskToRun != null) {
ThreadingImpl.taskToRun.run();
} else {
break;
}
}
}

ThreadingImpl.enterPhase(ThreadingImpl.PHASE_TICK);
ThreadingImpl.enterPhase(ThreadingImpl.PHASE_TICK);

Runnable deferredTask = this.deferredTask;
this.deferredTask = null;
Runnable deferredTask = this.deferredTask;
this.deferredTask = null;

if (deferredTask != null) {
deferredTask.run();
}
if (deferredTask != null) {
deferredTask.run();
}
}

@Inject(method = "startIntegratedServer", at = @At("HEAD"), cancellable = true)
private void deferStartIntegratedServer(LevelStorage.Session session, ResourcePackManager dataPackManager, SaveLoader saveLoader, boolean newWorld, CallbackInfo ci) {
if (FabricApiAutoTestClient.IS_AUTO_TEST && ThreadingImpl.taskToRun != null) {
if (ThreadingImpl.taskToRun != null) {
// don't start the integrated server (which busywaits) inside a task
deferredTask = () -> MinecraftClient.getInstance().startIntegratedServer(session, dataPackManager, saveLoader, newWorld);
ci.cancel();
Expand All @@ -115,16 +106,14 @@ private void deferStartIntegratedServer(LevelStorage.Session session, ResourcePa

@Inject(method = "startIntegratedServer", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;sleep(J)V", remap = false))
private void onStartIntegratedServerBusyWait(CallbackInfo ci) {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
// give the server a chance to tick too
preRunTasks(ci);
postRunTasks(ci);
}
// give the server a chance to tick too
preRunTasks(ci);
postRunTasks(ci);
}

@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;Z)V", at = @At("HEAD"), cancellable = true)
private void deferDisconnect(Screen disconnectionScreen, boolean transferring, CallbackInfo ci) {
if (FabricApiAutoTestClient.IS_AUTO_TEST && MinecraftClient.getInstance().getServer() != null && ThreadingImpl.taskToRun != null) {
if (MinecraftClient.getInstance().getServer() != null && ThreadingImpl.taskToRun != null) {
// don't disconnect (which busywaits) inside a task
deferredTask = () -> MinecraftClient.getInstance().disconnect(disconnectionScreen, transferring);
ci.cancel();
Expand All @@ -133,18 +122,14 @@ private void deferDisconnect(Screen disconnectionScreen, boolean transferring, C

@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;Z)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;render(Z)V", shift = At.Shift.AFTER))
private void onDisconnectBusyWait(CallbackInfo ci) {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
// give the server a chance to tick too
preRunTasks(ci);
postRunTasks(ci);
}
// give the server a chance to tick too
preRunTasks(ci);
postRunTasks(ci);
}

@Inject(method = "getInstance", at = @At("HEAD"))
private static void checkThreadOnGetInstance(CallbackInfoReturnable<MinecraftClient> cir) {
if (FabricApiAutoTestClient.IS_AUTO_TEST) {
// TODO: add suggestion of runOnClient etc when API methods are added
Preconditions.checkState(Thread.currentThread() != ThreadingImpl.testThread, "MinecraftClient.getInstance() cannot be called from the test thread");
}
// TODO: add suggestion of runOnClient etc when API methods are added
Preconditions.checkState(Thread.currentThread() != ThreadingImpl.testThread, "MinecraftClient.getInstance() cannot be called from the test thread");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package net.fabricmc.fabric.test.base.client.mixin;
package net.fabricmc.fabric.mixin.gametest.client;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
Expand All @@ -25,7 +25,7 @@

import net.minecraft.server.dedicated.MinecraftDedicatedServer;

import net.fabricmc.fabric.test.base.client.TestDedicatedServer;
import net.fabricmc.fabric.impl.gametest.client.TestDedicatedServer;

@Mixin(MinecraftDedicatedServer.class)
public abstract class MinecraftDedicatedServerMixin {
Expand Down
Loading

0 comments on commit 9af40ea

Please sign in to comment.