Make tests fail if error occurs during platform

This commit is contained in:
Nassim Jahnke committed 2026-03-30 20:40:26 +02:00
1 parent 8f8f5e72c0
commit fe6e18845b
8 files changed
+133 -25

No files matched your search

@@ -81,8 +81,9 @@ public class MappingDataLoader {
for (final Map.Entry<String, Tag> entry : globalIdentifiers.entrySet()) {
//noinspection unchecked
final ListTag<StringTag> value = (ListTag<StringTag>) entry.getValue();
final String[] array = new String[value.size()];
for (int i = 0, size = value.size(); i < size; i++) {
final int size = value.size();
final String[] array = new String[size];
for (int i = 0; i < size; i++) {
array[i] = value.get(i).getValue();
}
GLOBAL_IDENTIFIER_INDEXES.put(entry.getKey(), array);
@@ -249,7 +249,17 @@ public interface ProtocolManager {
*
* @return true if the executor has now been shut down
*/
boolean checkForMappingCompletion();
default boolean checkForMappingCompletion() {
return checkForMappingCompletion(false);
}
/**
* Shuts down the executor and uncaches mappings if all futures have been completed.
*
* @param propagateErrors whether to propagate errors from the futures to the caller
* @return true if the executor has now been shut down
*/
boolean checkForMappingCompletion(boolean propagateErrors);
/**
* Executes the given runnable asynchronously, adding a {@link CompletableFuture}
@@ -49,6 +49,20 @@ public final class NMSUtil {
}
}
public static Class<?> nms(String className, String... fallbackFullClassNames) throws ClassNotFoundException {
try {
return Class.forName(NMS + "." + className);
} catch (ClassNotFoundException ignored) {
}
for (final String fallbackFullClassName : fallbackFullClassNames) {
try {
return Class.forName(fallbackFullClassName);
} catch (ClassNotFoundException ignored) {
}
}
throw new ClassNotFoundException(className);
}
public static Class<?> obc(String className) throws ClassNotFoundException {
return Class.forName(BASE + "." + className);
}
@@ -97,6 +97,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -115,9 +116,7 @@ import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.logging.Level;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ProtocolManagerImpl implements ProtocolManager {
@@ -499,7 +498,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public boolean checkForMappingCompletion() {
public boolean checkForMappingCompletion(final boolean propagateErrors) {
mappingLoaderLock.readLock().lock();
try {
if (mappingsLoaded) {
@@ -511,6 +510,9 @@ public class ProtocolManagerImpl implements ProtocolManager {
if (!future.isDone()) {
return false;
}
if (propagateErrors) {
future.join();
}
}
shutdownLoaderExecutor();
@@ -522,7 +524,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
@Override
public void addMappingLoaderFuture(Class<? extends Protocol> protocolClass, Runnable runnable) {
CompletableFuture<Void> future = CompletableFuture.runAsync(runnable, mappingLoaderExecutor).exceptionally(mappingLoaderThrowable(protocolClass));
CompletableFuture<Void> future = CompletableFuture.runAsync(runnable, mappingLoaderExecutor)
.whenComplete(($, t) -> logIfErrored(protocolClass, t));
mappingLoaderLock.writeLock().lock();
try {
@@ -534,8 +537,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
@Override
public void addMappingLoaderFuture(Class<? extends Protocol> protocolClass, Class<? extends Protocol> dependsOn, Runnable runnable) {
CompletableFuture<Void> future = getMappingLoaderFuture(dependsOn)
.whenCompleteAsync((v, throwable) -> runnable.run(), mappingLoaderExecutor).exceptionally(mappingLoaderThrowable(protocolClass));
CompletableFuture<Void> future = getMappingLoaderFuture(dependsOn).thenRunAsync(runnable, mappingLoaderExecutor)
.whenComplete(($, t) -> logIfErrored(protocolClass, t));
mappingLoaderLock.writeLock().lock();
try {
@@ -586,10 +589,9 @@ public class ProtocolManagerImpl implements ProtocolManager {
MappingDataLoader.INSTANCE.clearCache();
}
private Function<Throwable, Void> mappingLoaderThrowable(Class<? extends Protocol> protocolClass) {
return throwable -> {
private void logIfErrored(final Class<? extends Protocol> protocolClass, @Nullable final Throwable throwable) {
if (throwable != null) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error during loading of " + protocolClass.getSimpleName(), throwable);
return null;
};
}
}
}
@@ -0,0 +1,28 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.common;
import org.junit.jupiter.api.Test;
final class APlatformBootstrapTest {
@Test
void platformLoads() throws InterruptedException {
PlatformTestLoader.ensureLoaded();
}
}
@@ -17,23 +17,12 @@
*/
package com.viaversion.viaversion.common;
import com.viaversion.viaversion.ViaManagerImpl;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.platform.NoopInjector;
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
import com.viaversion.viaversion.commands.ViaCommandHandler;
import com.viaversion.viaversion.common.dummy.TestPlatform;
import org.junit.jupiter.api.BeforeAll;
public abstract class PlatformTestBase {
@BeforeAll
static void loadPlatform() throws InterruptedException {
if (!Via.isLoaded()) {
ViaManagerImpl.initAndLoad(new TestPlatform(), new NoopInjector(), new ViaCommandHandler(), ViaPlatformLoader.NOOP);
}
while (!Via.getManager().getProtocolManager().hasLoadedMappings()) {
Thread.sleep(100);
}
PlatformTestLoader.ensureLoaded();
}
}
@@ -0,0 +1,63 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.common;
import com.viaversion.viaversion.ViaManagerImpl;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
import com.viaversion.viaversion.commands.ViaCommandHandler;
import com.viaversion.viaversion.common.dummy.TestPlatform;
import com.viaversion.viaversion.platform.NoopInjector;
import java.util.concurrent.CompletionException;
final class PlatformTestLoader {
private static boolean loaded;
private static Throwable failure;
static synchronized void ensureLoaded() throws InterruptedException {
if (loaded) {
return;
}
if (failure != null) {
throw new AssertionError("Platform bootstrap previously failed", failure);
}
try {
if (!Via.isLoaded()) {
ViaManagerImpl.initAndLoad(new TestPlatform(), new NoopInjector(), new ViaCommandHandler(false), ViaPlatformLoader.NOOP);
}
while (!Via.getManager().getProtocolManager().checkForMappingCompletion(true)) {
Thread.sleep(100);
}
loaded = true;
} catch (final CompletionException e) {
failure = e.getCause();
throw new AssertionError("Async mapping loading failed", e.getCause());
} catch (final InterruptedException e) {
failure = e;
Thread.currentThread().interrupt();
throw e;
} catch (final Throwable t) {
failure = t;
throw t;
}
}
}
@@ -0,0 +1 @@
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$ClassName