Skip to content

Commit

Permalink
Fail auto test server when pack resources fail to load
Browse files Browse the repository at this point in the history
  • Loading branch information
misode committed Jan 25, 2024
1 parent 3a75e77 commit 0c821c6
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/main/java/io/github/misode/packtest/LoadDiagnostics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.github.misode.packtest;

import java.util.ArrayList;
import java.util.List;

public class LoadDiagnostics {
private static final List<Diagnostic> DIAGNOSTICS = new ArrayList<>();

public static void error(String resource, String id, String message) {
DIAGNOSTICS.add(new Diagnostic(resource, id, message));
}

public static List<Diagnostic> loadErrors() {
return DIAGNOSTICS;
}

public record Diagnostic(String resource, String id, String message) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,37 @@

import com.google.common.collect.Lists;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.misode.packtest.LoadDiagnostics;
import io.github.misode.packtest.PackTest;
import net.minecraft.gametest.framework.*;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.BooleanSupplier;

/**
* Don't fail when initial batches is empty.
* Get list of batches after data packs have been loaded.
* Prints summary of resources that failed to load.
* Fails when no tests were loaded.
*/
@Mixin(GameTestServer.class)
public class GameTestServerMixin {
@Shadow @Final private static Logger LOGGER;

@Shadow @Nullable private MultipleTestTracker testTracker;

@ModifyExpressionValue(method = "create", at = @At(value = "INVOKE", target = "Ljava/util/Collection;isEmpty()Z"))
private static boolean isBatchesEmpty(boolean original) {
Expand All @@ -27,4 +44,30 @@ private ArrayList<GameTestBatch> modifyBatches(ArrayList<GameTestBatch> batches)
Collection<TestFunction> testFunctions = GameTestRegistry.getAllTestFunctions();
return Lists.newArrayList(GameTestRunner.groupTestsIntoBatches(testFunctions));
}

@Inject(method = "tickServer", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;info(Ljava/lang/String;Ljava/lang/Object;)V", ordinal = 0, shift = At.Shift.AFTER))
private void tickServer(BooleanSupplier booleanSupplier, CallbackInfo ci) {
List<LoadDiagnostics.Diagnostic> errors = LoadDiagnostics.loadErrors();
if (!errors.isEmpty()) {
LOGGER.info("{} resources failed to load :(", errors.size());
errors.forEach(diagnostic -> LOGGER.info(" - {} {}", diagnostic.resource(), diagnostic.id()));
}
}

@WrapOperation(method = "tickServer", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;info(Ljava/lang/String;Ljava/lang/Object;)V", ordinal = 2))
private void checkNoTests(Logger logger, String message, Object arg, Operation<Void> original) {
if (Objects.requireNonNull(this.testTracker).getTotalCount() == 0) {
LOGGER.info("No tests were loaded :(");
} else {
original.call(logger, message, arg);
}
}

@ModifyExpressionValue(method = "onServerExit", at = @At(value = "INVOKE", target = "Lnet/minecraft/gametest/framework/MultipleTestTracker;getFailedRequiredCount()I"))
private int onServerExit(int original) {
if (Objects.requireNonNull(this.testTracker).getTotalCount() == 0) {
return 1;
}
return original + LoadDiagnostics.loadErrors().size();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.misode.packtest.LoadDiagnostics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.storage.loot.LootDataType;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;

/**
* Catches loot table, predicate and item modifier errors.
* Improves error message.
*/
@Mixin(LootDataType.class)
public class LootDataTypeMixin {
@Shadow
@Final
private static Logger LOGGER;

@WrapOperation(method = "method_53267", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;[Ljava/lang/Object;)V"))
private void deserialize(Logger logger, String message, Object[] args, Operation<Void> original) {
String type = ((String)args[0]).substring(0, ((String)args[0]).length() - 1);
LoadDiagnostics.error(type, ((ResourceLocation)args[1]).toString(), (String)args[2]);
LOGGER.error("Couldn't parse {} {} - {}", type, args[1], args[2]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.misode.packtest.LoadDiagnostics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.RecipeManager;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;

/**
* Catch recipe errors and removes stacktrace.
*/
@Mixin(RecipeManager.class)
public class RecipeManagerMixin {
@Shadow
@Final
private static Logger LOGGER;

@WrapOperation(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"))
private void apply(Logger logger, String message, Object id, Object e, Operation<Void> original) {
String error = ((Exception)e).getMessage();
LoadDiagnostics.error("recipe", ((ResourceLocation)id).toString(), error);
LOGGER.error(message + " - {}", id, error);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.misode.packtest.LoadDiagnostics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.ServerAdvancementManager;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

/**
* Catch advancement errors.
*/
@Mixin(ServerAdvancementManager.class)
public class ServerAdvancementsManagerMixin {
@WrapOperation(method = "method_20723", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"))
private void apply(Logger logger, String message, Object id, Object error, Operation<Void> original) {
LoadDiagnostics.error("advancement", ((ResourceLocation)id).toString(), (String)error);
original.call(logger, message, id, error);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.misode.packtest.LoadDiagnostics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.ServerFunctionLibrary;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;

/**
* Catch function errors and removes stacktrace.
*/
@Mixin(ServerFunctionLibrary.class)
public class ServerFunctionLibraryMixin {
@Shadow
@Final
private static Logger LOGGER;

@WrapOperation(method = "method_29457", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"))
private static void catchFunctionError(Logger logger, String message, Object id, Object e, Operation<Void> original) {
String error = ((Exception)e).getMessage().replaceFirst("^[A-Za-z0-9.]+Exception: ", "");
LoadDiagnostics.error("function", ((ResourceLocation)id).toString(), error);
LOGGER.error(message + " - {}", id, error);
}
}
46 changes: 46 additions & 0 deletions src/main/java/io/github/misode/packtest/mixin/TagLoaderMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.serialization.DataResult;
import io.github.misode.packtest.LoadDiagnostics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagFile;
import net.minecraft.tags.TagLoader;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;

import java.util.function.Consumer;

/**
* Catch tag errors and removes stacktrace.
* Removes the duplicate data result error.
*/
@Mixin(TagLoader.class)
public class TagLoaderMixin {
@Shadow
@Final
private static Logger LOGGER;

@WrapOperation(method = "load", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/DataResult;getOrThrow(ZLjava/util/function/Consumer;)Ljava/lang/Object;"))
private static Object removeDuplicateError(DataResult<Object> dataResult, boolean allowPartial, Consumer<String> onError, Operation<TagFile> original) {
return dataResult.getOrThrow(allowPartial, (error) -> {});
}

@WrapOperation(method = "load", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;[Ljava/lang/Object;)V"))
private static void catchTagError(Logger logger, String message, Object[] args, Operation<Void> original) {
String error = ((Exception)args[3]).getMessage().replaceFirst("^[A-Za-z0-9.]+Exception: ", "");
String type = ((ResourceLocation)args[1]).getPath().replaceFirst("tags/", "").replaceFirst("s?/.*", "");
LoadDiagnostics.error(type + " tag", ((ResourceLocation)args[0]).toString(), error);
LOGGER.error("Couldn't read {} tag {} - {}", type, args[0], error);
}

@WrapOperation(method = "method_33175", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"))
private static void catchTagReferenceError(Logger logger, String message, Object id, Object refs, Operation<Void> original) {
LoadDiagnostics.error("tag", ((ResourceLocation)id).toString(), "Missing references: " + refs);
original.call(logger, message, id, refs);
}
}
5 changes: 5 additions & 0 deletions src/main/resources/packtest.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
"GameTestSequenceMixin",
"GameTestServerMixin",
"LogTestReporterMixin",
"LootDataTypeMixin",
"MinecraftServerMixin",
"PlayerListMixin",
"RecipeManagerMixin",
"ReloadableServerResourcesMixin",
"ReportGameListenerMixin",
"ServerAdvancementsManagerMixin",
"ServerFunctionLibraryMixin",
"ServerPlayerMixin",
"StructureUtilsMixin",
"TagLoaderMixin",
"TestCommandMixin"
],
"server": [
Expand Down

0 comments on commit 0c821c6

Please sign in to comment.