This commit is contained in:
Brian Neumann-Fopiano committed 2026-08-13 12:38:08 -04:00
1 parent 14b6280668
commit 1586b4bd1a
68 files changed
+733 -211

No files matched your search

@@ -1,9 +1,13 @@
package art.arcane.iris.core.lifecycle;
import art.arcane.volmlib.util.bukkit.WorldIdentity;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.plugin.PluginManager;
import org.junit.Test;
import org.mockito.MockedStatic;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
@@ -16,10 +20,43 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class WorldLifecycleUnloadAsyncTest {
@Test
public void manualUnloadFallbackDispatchesWorldUnloadEvent() {
World world = mock(World.class);
PluginManager pluginManager = mock(PluginManager.class);
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
bukkit.when(Bukkit::getPluginManager).thenReturn(pluginManager);
assertTrue(WorldLifecycleSupport.announceManualWorldUnload(world));
}
verify(pluginManager).callEvent(any(WorldUnloadEvent.class));
}
@Test
public void manualUnloadFallbackHonorsCancelledWorldUnloadEvent() {
World world = mock(World.class);
PluginManager pluginManager = mock(PluginManager.class);
doAnswer(invocation -> {
WorldUnloadEvent event = invocation.getArgument(0);
event.setCancelled(true);
return null;
}).when(pluginManager).callEvent(any(WorldUnloadEvent.class));
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
bukkit.when(Bukkit::getPluginManager).thenReturn(pluginManager);
assertFalse(WorldLifecycleSupport.announceManualWorldUnload(world));
}
}
@Test
public void reflectedAsyncUnloadWaitsForTrueCallback() throws Exception {
CallbackServer server = new CallbackServer();
@@ -192,22 +192,22 @@ public class WorldReplacementBootstrapTest {
}
@Test
public void rejectsChangedLevelRootBeforeTouchingStagedStorage() throws Exception {
public void skipsChangedLevelRootWithoutTouchingStagedStorage() throws Exception {
Transaction transaction = stagedTransaction(Phase.ARMED, true, "original");
configureReplacement(transaction);
Path otherLevelRoot = Files.createDirectories(serverRoot.resolve("renamed-world"));
assertThrows(
IOException.class,
() -> WorldReplacementBootstrap.reconcile(
dataDirectory,
otherLevelRoot,
bukkitConfiguration,
ignored -> {
}
)
WorldReplacementBootstrap.ReconcileResult result = WorldReplacementBootstrap.reconcile(
dataDirectory,
otherLevelRoot,
bukkitConfiguration,
ignored -> {
}
);
assertEquals(1, result.skipped());
assertEquals(0, result.published());
assertEquals(0, result.rolledBack());
assertEquals("original", Files.readString(target.worldDirectory().resolve("original.txt")));
assertTrue(Files.isDirectory(paths(transaction).stage()));
assertFalse(Files.exists(paths(transaction).backup()));
@@ -280,6 +280,28 @@ public class WorldReplacementBootstrapTest {
}
}
@Test
public void skipsJournalStagedAgainstAnotherLevelRootInsteadOfAborting() throws Exception {
Transaction transaction = stagedTransaction(Phase.CLEANUP_PENDING, true, "original");
Path otherLevelRoot = Files.createDirectories(serverRoot.resolve("renamed-world"));
WorldReplacementBootstrap.ReconcileResult result = WorldReplacementBootstrap.reconcile(
dataDirectory,
otherLevelRoot,
bukkitConfiguration,
ignored -> {
}
);
assertEquals(1, result.skipped());
assertEquals(0, result.published());
assertEquals(0, result.rolledBack());
assertEquals(0, result.retained());
assertTrue(Files.exists(dataDirectory
.resolve(WorldReplacementJournal.DIRECTORY_NAME)
.resolve(transaction.id() + ".properties")));
}
private WorldReplacementBootstrap.ReconcileResult reconcile() throws Exception {
return WorldReplacementBootstrap.reconcile(
dataDirectory,
@@ -108,6 +108,23 @@ public class WorldReplacementFilesystemTest {
assertFalse(Files.exists(paths.backup()));
}
@Test
public void rejectsUnmigratedRetainedWorldAtAdmission() throws Exception {
WorldReplacementFilesystem.ReplacementPaths paths = paths("admit-missing-paper-metadata", TRANSACTION_ID);
Files.createDirectories(paths.target());
Files.writeString(paths.target().resolve("original.txt"), "original");
IOException failure = assertThrows(
IOException.class,
() -> WorldReplacementFilesystem.requireExistingTarget(paths)
);
assertTrue(failure.getMessage().contains("missing Paper world metadata"));
assertTrue(failure.getMessage().contains("load the world once on this server"));
assertFalse(Files.exists(paths.stage()));
assertFalse(Files.exists(paths.backup()));
}
@Test
public void publishesReplacementWithoutCreatingBackupForAbsentTarget() throws Exception {
WorldReplacementFilesystem.ReplacementPaths paths = paths("publish-absent", TRANSACTION_ID);
@@ -8,7 +8,9 @@ import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -25,7 +27,7 @@ public class IrisLoggingTest {
@Test
public void contextualReportPrintsFullStacktraceWithBoundPlatform() {
IrisPlatform platform = mock(IrisPlatform.class);
IrisPlatform platform = mock(IrisPlatform.class, CALLS_REAL_METHODS);
IrisPlatforms.bind(platform);
IllegalStateException failure = new IllegalStateException("outer", new IllegalArgumentException("inner"));
ByteArrayOutputStream output = new ByteArrayOutputStream();
@@ -38,10 +40,29 @@ public class IrisLoggingTest {
}
verify(platform).log(LogLevel.ERROR, "Runtime world creation failed.");
verify(platform).reportError("Runtime world creation failed.", failure);
verify(platform).reportError(failure);
String text = output.toString(StandardCharsets.UTF_8);
assertTrue(text.contains("IllegalStateException"));
assertTrue(text.contains("IllegalArgumentException"));
assertTrue(text.contains("inner"));
}
@Test
public void contextualReportHonorsPlatformOverrideSuppression() {
IrisPlatform platform = mock(IrisPlatform.class);
IrisPlatforms.bind(platform);
IllegalStateException failure = new IllegalStateException("suppressed");
ByteArrayOutputStream output = new ByteArrayOutputStream();
PrintStream originalErr = System.err;
System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8));
try {
IrisLogging.reportError("Throttled failure.", failure);
} finally {
System.setErr(originalErr);
}
verify(platform).reportError("Throttled failure.", failure);
assertFalse(output.toString(StandardCharsets.UTF_8).contains("suppressed"));
}
}