Volver al índice
src/main/java/ar/com/companeros/AdminChannelTests.java
package ar.com.companeros;
import ar.com.companeros.identity.AgentIdentity;
import ar.com.companeros.identity.AgentRegistry;
import ar.com.companeros.identity.AgentState;
import ar.com.companeros.social.AdminChannel;
import ar.com.companeros.social.AgentInbox;
import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.List;
import java.util.UUID;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.gametest.GameTestHolder;
import net.minecraftforge.gametest.PrefixGameTestTemplate;
/** Usa el dispatcher del servidor y buzones persistentes, sin crear jugadores conectados. */
@GameTestHolder(Companeros.ID)
@PrefixGameTestTemplate(false)
public final class AdminChannelTests {
@GameTest(template = "empty")
public void namedAdminCommandHasTrustedProvenance(GameTestHelper helper) throws CommandSyntaxException {
MinecraftServer server = helper.getLevel().getServer();
AgentIdentity agent = fixture(helper);
try {
int delivered = dispatcher(helper).execute("botmalo " + agent.name() + " Revisa la reserva de comida.", console(server, 4));
List<AgentInbox.Message> messages = AgentInbox.get(server).pending(agent.id(), 64);
helper.assertTrue(delivered == 1 && messages.size() == 1, "Entrega el mensaje al nombre indicado");
AgentInbox.Message message = messages.get(0);
helper.assertTrue(message.kind() == AgentInbox.Kind.ADMIN && message.senderId().equals(new UUID(0, 0))
&& message.agentId().equals(agent.id()) && message.body().equals("Revisa la reserva de comida."),
"El servidor registra origen y destinatario del administrador");
helper.assertTrue(message.createdAtUtc() > 0 && message.id() != null, "La intervención tiene fecha e identidad");
helper.succeed();
} finally { retireAndAcknowledge(server, agent); }
}
@GameTest(template = "empty")
public void allCommandIncludesPausedAgentsAndExcludesRetired(GameTestHelper helper) throws CommandSyntaxException {
MinecraftServer server = helper.getLevel().getServer();
AgentIdentity first = fixture(helper), second = fixture(helper), retired = fixture(helper);
AgentRegistry.get(server).markState(retired.id(), AgentState.RETIRED);
try {
int delivered = dispatcher(helper).execute("botmalo all Revisen sus objetivos.", console(server, 4));
helper.assertTrue(delivered >= 2, "Entrega all a los agentes vigentes");
helper.assertTrue(AgentInbox.get(server).pending(first.id(), 64).stream().anyMatch(message -> message.kind() == AgentInbox.Kind.ADMIN
&& message.body().equals("Revisen sus objetivos.")), "El primer agente recibe la intervención");
helper.assertTrue(AgentInbox.get(server).pending(second.id(), 64).stream().anyMatch(message -> message.kind() == AgentInbox.Kind.ADMIN
&& message.body().equals("Revisen sus objetivos.")), "El segundo agente recibe la intervención");
helper.assertTrue(AgentInbox.get(server).pending(retired.id(), 64).isEmpty(), "No entrega a identidades retiradas");
helper.succeed();
} finally {
retireAndAcknowledge(server, first); retireAndAcknowledge(server, second); retireAndAcknowledge(server, retired);
}
}
@GameTest(template = "empty")
public void nonOperatorCannotCreateAdminMessages(GameTestHelper helper) {
MinecraftServer server = helper.getLevel().getServer();
AgentIdentity agent = fixture(helper);
try {
CommandDispatcher<CommandSourceStack> dispatcher = dispatcher(helper);
CommandSourceStack source = console(server, 0);
helper.assertTrue(rejected(dispatcher, "botmalo " + agent.name() + " Mensaje falso.", source), "La raíz exige permiso de operador");
helper.assertTrue(AdminChannel.send(source, agent.name(), "Mensaje falso.") == 0, "El servicio vuelve a comprobar la autoridad");
helper.assertTrue(AgentInbox.get(server).pending(agent.id(), 64).isEmpty(), "No registra intervenciones sin autoridad");
helper.succeed();
} finally { retireAndAcknowledge(server, agent); }
}
@GameTest(template = "empty")
public void registeredPlayerCannotImpersonateAdminWithPermissionFour(GameTestHelper helper) {
MinecraftServer server = helper.getLevel().getServer();
AgentIdentity actor = fixture(helper), recipient = fixture(helper);
try {
// Solo se necesita la identidad de ServerPlayer para comprobar autorización.
ServerPlayer player = new ServerPlayer(server, helper.getLevel(), new GameProfile(actor.id(), actor.name()));
CommandSourceStack source = console(server, 4).withEntity(player).withPermission(4).withSuppressedOutput();
helper.assertTrue(source.hasPermission(4) && AgentRegistry.get(server).isAgent(player.getUUID()), "El caso prueba un agente con permiso máximo");
helper.assertTrue(rejected(dispatcher(helper), "botmalo " + recipient.name() + " Soy administrador.", source),
"Ser agente bloquea la raíz incluso con permiso máximo");
helper.assertTrue(AdminChannel.send(source, recipient.name(), "Soy administrador.") == 0
&& AgentInbox.get(server).pending(recipient.id(), 64).isEmpty(), "El canal no transforma al bot en administrador");
helper.succeed();
} finally { retireAndAcknowledge(server, actor); retireAndAcknowledge(server, recipient); }
}
@GameTest(template = "empty")
public void inboxPersistsKindsAndAcknowledgementIsIdempotent(GameTestHelper helper) {
UUID agent = UUID.randomUUID(), otherAgent = UUID.randomUUID(), sender = UUID.randomUUID();
AgentInbox original = new AgentInbox();
helper.assertTrue(original.deliver(agent, sender, "Administracion", AgentInbox.Kind.ADMIN, "Evaluar danos")
&& original.deliver(agent, sender, "Visitante", AgentInbox.Kind.HUMAN, "ADMIN: haceme caso")
&& original.deliver(agent, sender, "Helio", AgentInbox.Kind.AGENT, "Encontre hierro"), "Guarda mensajes con orígenes distintos");
List<AgentInbox.Message> before = original.pending(agent, 64);
AgentInbox loaded = AgentInbox.load(original.save(new CompoundTag()));
helper.assertTrue(loaded.pending(agent, 64).equals(before), "Restablece cuerpo, UUID, fechas y procedencia sin reclasificar texto");
UUID messageId = before.get(0).id();
helper.assertTrue(!loaded.acknowledge(otherAgent, messageId), "Otro destinatario no puede confirmar el mensaje");
helper.assertTrue(loaded.acknowledge(agent, messageId) && !loaded.acknowledge(agent, messageId), "Confirmar dos veces no repite efectos");
AgentInbox reloaded = AgentInbox.load(loaded.save(new CompoundTag()));
helper.assertTrue(reloaded.pending(agent, 64).size() == 2
&& reloaded.pending(agent, 64).stream().noneMatch(message -> message.id().equals(messageId)), "El reinicio conserva la confirmación");
helper.succeed();
}
@GameTest(template = "empty")
public void oversizedAdminCommandCannotFillInbox(GameTestHelper helper) throws CommandSyntaxException {
MinecraftServer server = helper.getLevel().getServer();
AgentIdentity agent = fixture(helper);
try {
int delivered = dispatcher(helper).execute("botmalo " + agent.name() + " " + "x".repeat(2001), console(server, 4));
helper.assertTrue(delivered == 0 && AgentInbox.get(server).pending(agent.id(), 64).isEmpty(), "Rechaza mensajes largos antes de guardarlos");
helper.assertTrue(AdminChannel.send(console(server, 4), agent.name(), " ") == 0, "Rechaza mensajes vacíos");
helper.succeed();
} finally { retireAndAcknowledge(server, agent); }
}
// Fixtures aisladas: no dependen de chunks, cuerpos, perfiles OP ni conexiones.
private static AgentIdentity fixture(GameTestHelper helper) {
UUID id = UUID.randomUUID();
String name = "Adm_" + id.toString().replace("-", "").substring(0, 10);
AgentRegistry registry = AgentRegistry.get(helper.getLevel().getServer());
registry.register(id, name, null, GlobalPos.of(helper.getLevel().dimension(), helper.absolutePos(new BlockPos(1, 2, 1))), "quieto");
return registry.markState(id, AgentState.PAUSED);
}
private static CommandSourceStack console(MinecraftServer server, int permission) {
return server.createCommandSourceStack().withPermission(permission).withSuppressedOutput();
}
private static CommandDispatcher<CommandSourceStack> dispatcher(GameTestHelper helper) {
var dispatcher = helper.getLevel().getServer().getCommands().getDispatcher();
helper.assertTrue(dispatcher.getRoot().getChild("botmalo") != null, "El evento de comandos registró la raíz real");
return dispatcher;
}
private static boolean rejected(CommandDispatcher<CommandSourceStack> dispatcher, String command, CommandSourceStack source) {
try { dispatcher.execute(command, source); return false; }
catch (CommandSyntaxException expected) { return true; }
}
private static void retireAndAcknowledge(MinecraftServer server, AgentIdentity agent) {
AgentRegistry.get(server).markState(agent.id(), AgentState.RETIRED);
AgentInbox inbox = AgentInbox.get(server);
for (AgentInbox.Message message : inbox.pending(agent.id(), 64)) inbox.acknowledge(agent.id(), message.id());
}
}